PostgreSQL Source Code  git master
spgutils.c File Reference
#include "postgres.h"
#include "access/amvalidate.h"
#include "access/htup_details.h"
#include "access/reloptions.h"
#include "access/spgist_private.h"
#include "access/transam.h"
#include "access/xact.h"
#include "catalog/pg_amop.h"
#include "commands/vacuum.h"
#include "storage/bufmgr.h"
#include "storage/indexfsm.h"
#include "storage/lmgr.h"
#include "utils/builtins.h"
#include "utils/catcache.h"
#include "utils/index_selfuncs.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
Include dependency graph for spgutils.c:

Go to the source code of this file.

Macros

#define GET_LUP(c, f)   (&(c)->lastUsedPages.cachedPage[((unsigned int) (f)) % SPGIST_CACHED_PAGES])
 

Functions

Datum spghandler (PG_FUNCTION_ARGS)
 
static void fillTypeDesc (SpGistTypeDesc *desc, Oid type)
 
SpGistCachespgGetCache (Relation index)
 
void initSpGistState (SpGistState *state, Relation index)
 
Buffer SpGistNewBuffer (Relation index)
 
void SpGistUpdateMetaPage (Relation index)
 
static Buffer allocNewBuffer (Relation index, int flags)
 
Buffer SpGistGetBuffer (Relation index, int flags, int needSpace, bool *isNew)
 
void SpGistSetLastUsedPage (Relation index, Buffer buffer)
 
void SpGistInitPage (Page page, uint16 f)
 
void SpGistInitBuffer (Buffer b, uint16 f)
 
void SpGistInitMetapage (Page page)
 
byteaspgoptions (Datum reloptions, bool validate)
 
unsigned int SpGistGetTypeSize (SpGistTypeDesc *att, Datum datum)
 
static void memcpyDatum (void *target, SpGistTypeDesc *att, Datum datum)
 
SpGistLeafTuple spgFormLeafTuple (SpGistState *state, ItemPointer heapPtr, Datum datum, bool isnull)
 
SpGistNodeTuple spgFormNodeTuple (SpGistState *state, Datum label, bool isnull)
 
SpGistInnerTuple spgFormInnerTuple (SpGistState *state, bool hasPrefix, Datum prefix, int nNodes, SpGistNodeTuple *nodes)
 
SpGistDeadTuple spgFormDeadTuple (SpGistState *state, int tupstate, BlockNumber blkno, OffsetNumber offnum)
 
DatumspgExtractNodeLabels (SpGistState *state, SpGistInnerTuple innerTuple)
 
OffsetNumber SpGistPageAddNewItem (SpGistState *state, Page page, Item item, Size size, OffsetNumber *startOffset, bool errorOK)
 
bool spgproperty (Oid index_oid, int attno, IndexAMProperty prop, const char *propname, bool *res, bool *isnull)
 

Macro Definition Documentation

◆ GET_LUP

#define GET_LUP (   c,
 
)    (&(c)->lastUsedPages.cachedPage[((unsigned int) (f)) % SPGIST_CACHED_PAGES])

Definition at line 320 of file spgutils.c.

Referenced by SpGistGetBuffer(), and SpGistSetLastUsedPage().

Function Documentation

◆ allocNewBuffer()

static Buffer allocNewBuffer ( Relation  index,
int  flags 
)
static

Definition at line 343 of file spgutils.c.

References SpGistLastUsedPage::blkno, BufferGetBlockNumber(), BufferGetPage, SpGistLUPCache::cachedPage, SpGistLastUsedPage::freeSpace, GBUF_INNER_PARITY, GBUF_NULLS, GBUF_PARITY_MASK, GBUF_REQ_LEAF, GBUF_REQ_NULLS, SpGistCache::lastUsedPages, PageGetExactFreeSpace(), spgGetCache(), SPGIST_LEAF, SPGIST_NULLS, SpGistInitBuffer(), SpGistNewBuffer(), and UnlockReleaseBuffer().

Referenced by SpGistGetBuffer().

344 {
345  SpGistCache *cache = spgGetCache(index);
346  uint16 pageflags = 0;
347 
348  if (GBUF_REQ_LEAF(flags))
349  pageflags |= SPGIST_LEAF;
350  if (GBUF_REQ_NULLS(flags))
351  pageflags |= SPGIST_NULLS;
352 
353  for (;;)
354  {
355  Buffer buffer;
356 
357  buffer = SpGistNewBuffer(index);
358  SpGistInitBuffer(buffer, pageflags);
359 
360  if (pageflags & SPGIST_LEAF)
361  {
362  /* Leaf pages have no parity concerns, so just use it */
363  return buffer;
364  }
365  else
366  {
367  BlockNumber blkno = BufferGetBlockNumber(buffer);
368  int blkFlags = GBUF_INNER_PARITY(blkno);
369 
370  if ((flags & GBUF_PARITY_MASK) == blkFlags)
371  {
372  /* Page has right parity, use it */
373  return buffer;
374  }
375  else
376  {
377  /* Page has wrong parity, record it in cache and try again */
378  if (pageflags & SPGIST_NULLS)
379  blkFlags |= GBUF_NULLS;
380  cache->lastUsedPages.cachedPage[blkFlags].blkno = blkno;
381  cache->lastUsedPages.cachedPage[blkFlags].freeSpace =
383  UnlockReleaseBuffer(buffer);
384  }
385  }
386  }
387 }
SpGistCache * spgGetCache(Relation index)
Definition: spgutils.c:103
#define SPGIST_NULLS
uint32 BlockNumber
Definition: block.h:31
SpGistLUPCache lastUsedPages
SpGistLastUsedPage cachedPage[SPGIST_CACHED_PAGES]
#define GBUF_REQ_NULLS(flags)
unsigned short uint16
Definition: c.h:358
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3398
#define GBUF_INNER_PARITY(x)
void SpGistInitBuffer(Buffer b, uint16 f)
Definition: spgutils.c:553
#define BufferGetPage(buffer)
Definition: bufmgr.h:159
Buffer SpGistNewBuffer(Relation index)
Definition: spgutils.c:215
#define GBUF_PARITY_MASK
#define GBUF_NULLS
Size PageGetExactFreeSpace(Page page)
Definition: bufpage.c:632
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2623
#define SPGIST_LEAF
int Buffer
Definition: buf.h:23
#define GBUF_REQ_LEAF(flags)

◆ fillTypeDesc()

static void fillTypeDesc ( SpGistTypeDesc desc,
Oid  type 
)
static

Definition at line 92 of file spgutils.c.

References SpGistTypeDesc::attbyval, SpGistTypeDesc::attlen, get_typlenbyval(), SpGistTypeDesc::type, and generate_unaccent_rules::type.

Referenced by spgGetCache().

93 {
94  desc->type = type;
95  get_typlenbyval(type, &desc->attlen, &desc->attbyval);
96 }
void get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval)
Definition: lsyscache.c:2029

◆ initSpGistState()

void initSpGistState ( SpGistState state,
Relation  index 
)

Definition at line 185 of file spgutils.c.

References SpGistState::attLabelType, SpGistCache::attLabelType, SpGistState::attLeafType, SpGistCache::attLeafType, SpGistState::attPrefixType, SpGistCache::attPrefixType, SpGistState::attType, SpGistCache::attType, SpGistState::config, SpGistCache::config, SpGistState::deadTupleStorage, GetTopTransactionIdIfAny(), SpGistState::isBuild, SpGistState::myXid, palloc0(), SGDTSIZE, and spgGetCache().

Referenced by spgbeginscan(), spgbuild(), spginsert(), and spgvacuumscan().

186 {
187  SpGistCache *cache;
188 
189  /* Get cached static information about index */
190  cache = spgGetCache(index);
191 
192  state->config = cache->config;
193  state->attType = cache->attType;
194  state->attLeafType = cache->attLeafType;
195  state->attPrefixType = cache->attPrefixType;
196  state->attLabelType = cache->attLabelType;
197 
198  /* Make workspace for constructing dead tuples */
200 
201  /* Set XID to use in redirection tuples */
202  state->myXid = GetTopTransactionIdIfAny();
203 
204  /* Assume we're not in an index build (spgbuild will override) */
205  state->isBuild = false;
206 }
SpGistTypeDesc attLeafType
SpGistTypeDesc attPrefixType
SpGistCache * spgGetCache(Relation index)
Definition: spgutils.c:103
#define SGDTSIZE
SpGistTypeDesc attLeafType
SpGistTypeDesc attType
SpGistTypeDesc attLabelType
SpGistTypeDesc attType
spgConfigOut config
TransactionId myXid
TransactionId GetTopTransactionIdIfAny(void)
Definition: xact.c:409
spgConfigOut config
void * palloc0(Size size)
Definition: mcxt.c:980
char * deadTupleStorage
SpGistTypeDesc attLabelType
SpGistTypeDesc attPrefixType

◆ memcpyDatum()

static void memcpyDatum ( void *  target,
SpGistTypeDesc att,
Datum  datum 
)
static

Definition at line 628 of file spgutils.c.

References SpGistTypeDesc::attbyval, SpGistTypeDesc::attlen, DatumGetPointer, and VARSIZE_ANY.

Referenced by spgFormInnerTuple(), spgFormLeafTuple(), and spgFormNodeTuple().

629 {
630  unsigned int size;
631 
632  if (att->attbyval)
633  {
634  memcpy(target, &datum, sizeof(Datum));
635  }
636  else
637  {
638  size = (att->attlen > 0) ? att->attlen : VARSIZE_ANY(datum);
639  memcpy(target, DatumGetPointer(datum), size);
640  }
641 }
uintptr_t Datum
Definition: postgres.h:367
#define VARSIZE_ANY(PTR)
Definition: postgres.h:335
#define DatumGetPointer(X)
Definition: postgres.h:549

◆ spgExtractNodeLabels()

Datum* spgExtractNodeLabels ( SpGistState state,
SpGistInnerTuple  innerTuple 
)

Definition at line 839 of file spgutils.c.

References elog, ERROR, i, IndexTupleHasNulls, SpGistInnerTupleData::nNodes, palloc(), SGITITERATE, SGITNODEPTR, and SGNTDATUM.

Referenced by spgdoinsert(), and spgInitInnerConsistentIn().

840 {
841  Datum *nodeLabels;
842  int i;
843  SpGistNodeTuple node;
844 
845  /* Either all the labels must be NULL, or none. */
846  node = SGITNODEPTR(innerTuple);
847  if (IndexTupleHasNulls(node))
848  {
849  SGITITERATE(innerTuple, i, node)
850  {
851  if (!IndexTupleHasNulls(node))
852  elog(ERROR, "some but not all node labels are null in SPGiST inner tuple");
853  }
854  /* They're all null, so just return NULL */
855  return NULL;
856  }
857  else
858  {
859  nodeLabels = (Datum *) palloc(sizeof(Datum) * innerTuple->nNodes);
860  SGITITERATE(innerTuple, i, node)
861  {
862  if (IndexTupleHasNulls(node))
863  elog(ERROR, "some but not all node labels are null in SPGiST inner tuple");
864  nodeLabels[i] = SGNTDATUM(node, state);
865  }
866  return nodeLabels;
867  }
868 }
#define SGITNODEPTR(x)
#define SGITITERATE(x, i, nt)
#define IndexTupleHasNulls(itup)
Definition: itup.h:72
#define ERROR
Definition: elog.h:43
uintptr_t Datum
Definition: postgres.h:367
void * palloc(Size size)
Definition: mcxt.c:949
#define elog(elevel,...)
Definition: elog.h:228
int i
#define SGNTDATUM(x, s)

◆ spgFormDeadTuple()

SpGistDeadTuple spgFormDeadTuple ( SpGistState state,
int  tupstate,
BlockNumber  blkno,
OffsetNumber  offnum 
)

Definition at line 809 of file spgutils.c.

References Assert, SpGistState::deadTupleStorage, InvalidOffsetNumber, InvalidTransactionId, ItemPointerSet, ItemPointerSetInvalid, SpGistState::myXid, SpGistDeadTupleData::nextOffset, SpGistDeadTupleData::pointer, SGDTSIZE, SpGistDeadTupleData::size, SPGIST_REDIRECT, TransactionIdIsValid, SpGistDeadTupleData::tupstate, and SpGistDeadTupleData::xid.

Referenced by spgAddNodeAction(), spgPageIndexMultiDelete(), and spgRedoAddNode().

811 {
813 
814  tuple->tupstate = tupstate;
815  tuple->size = SGDTSIZE;
817 
818  if (tupstate == SPGIST_REDIRECT)
819  {
820  ItemPointerSet(&tuple->pointer, blkno, offnum);
822  tuple->xid = state->myXid;
823  }
824  else
825  {
827  tuple->xid = InvalidTransactionId;
828  }
829 
830  return tuple;
831 }
#define SGDTSIZE
#define SPGIST_REDIRECT
ItemPointerData pointer
SpGistDeadTupleData * SpGistDeadTuple
#define InvalidTransactionId
Definition: transam.h:31
TransactionId myXid
unsigned int tupstate
char * deadTupleStorage
OffsetNumber nextOffset
#define InvalidOffsetNumber
Definition: off.h:26
#define Assert(condition)
Definition: c.h:739
#define ItemPointerSetInvalid(pointer)
Definition: itemptr.h:172
#define TransactionIdIsValid(xid)
Definition: transam.h:41
#define ItemPointerSet(pointer, blockNumber, offNum)
Definition: itemptr.h:127

◆ spgFormInnerTuple()

SpGistInnerTuple spgFormInnerTuple ( SpGistState state,
bool  hasPrefix,
Datum  prefix,
int  nNodes,
SpGistNodeTuple nodes 
)

Definition at line 726 of file spgutils.c.

References SpGistState::attPrefixType, elog, ereport, errcode(), errhint(), errmsg(), ERROR, i, IndexTupleSize, memcpyDatum(), SpGistInnerTupleData::nNodes, palloc0(), SpGistInnerTupleData::prefixSize, SGDTSIZE, SGITDATAPTR, SGITHDRSZ, SGITMAXNNODES, SGITMAXPREFIXSIZE, SGITMAXSIZE, SGITNODEPTR, SpGistInnerTupleData::size, SPGIST_PAGE_CAPACITY, and SpGistGetTypeSize().

Referenced by addNode(), doPickSplit(), and spgSplitNodeAction().

728 {
729  SpGistInnerTuple tup;
730  unsigned int size;
731  unsigned int prefixSize;
732  int i;
733  char *ptr;
734 
735  /* Compute size needed */
736  if (hasPrefix)
737  prefixSize = SpGistGetTypeSize(&state->attPrefixType, prefix);
738  else
739  prefixSize = 0;
740 
741  size = SGITHDRSZ + prefixSize;
742 
743  /* Note: we rely on node tuple sizes to be maxaligned already */
744  for (i = 0; i < nNodes; i++)
745  size += IndexTupleSize(nodes[i]);
746 
747  /*
748  * Ensure that we can replace the tuple with a dead tuple later. This
749  * test is unnecessary given current tuple layouts, but let's be safe.
750  */
751  if (size < SGDTSIZE)
752  size = SGDTSIZE;
753 
754  /*
755  * Inner tuple should be small enough to fit on a page
756  */
757  if (size > SPGIST_PAGE_CAPACITY - sizeof(ItemIdData))
758  ereport(ERROR,
759  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
760  errmsg("SP-GiST inner tuple size %zu exceeds maximum %zu",
761  (Size) size,
762  SPGIST_PAGE_CAPACITY - sizeof(ItemIdData)),
763  errhint("Values larger than a buffer page cannot be indexed.")));
764 
765  /*
766  * Check for overflow of header fields --- probably can't fail if the
767  * above succeeded, but let's be paranoid
768  */
769  if (size > SGITMAXSIZE ||
770  prefixSize > SGITMAXPREFIXSIZE ||
771  nNodes > SGITMAXNNODES)
772  elog(ERROR, "SPGiST inner tuple header field is too small");
773 
774  /* OK, form the tuple */
775  tup = (SpGistInnerTuple) palloc0(size);
776 
777  tup->nNodes = nNodes;
778  tup->prefixSize = prefixSize;
779  tup->size = size;
780 
781  if (hasPrefix)
782  memcpyDatum(SGITDATAPTR(tup), &state->attPrefixType, prefix);
783 
784  ptr = (char *) SGITNODEPTR(tup);
785 
786  for (i = 0; i < nNodes; i++)
787  {
788  SpGistNodeTuple node = nodes[i];
789 
790  memcpy(ptr, node, IndexTupleSize(node));
791  ptr += IndexTupleSize(node);
792  }
793 
794  return tup;
795 }
#define SGITNODEPTR(x)
SpGistTypeDesc attPrefixType
SpGistInnerTupleData * SpGistInnerTuple
int errhint(const char *fmt,...)
Definition: elog.c:1069
#define SGITMAXPREFIXSIZE
#define SGDTSIZE
int errcode(int sqlerrcode)
Definition: elog.c:608
#define ERROR
Definition: elog.h:43
unsigned int prefixSize
#define SGITMAXSIZE
#define SGITDATAPTR(x)
#define SGITMAXNNODES
#define ereport(elevel, rest)
Definition: elog.h:141
unsigned int SpGistGetTypeSize(SpGistTypeDesc *att, Datum datum)
Definition: spgutils.c:610
void * palloc0(Size size)
Definition: mcxt.c:980
#define SPGIST_PAGE_CAPACITY
size_t Size
Definition: c.h:467
static void memcpyDatum(void *target, SpGistTypeDesc *att, Datum datum)
Definition: spgutils.c:628
int errmsg(const char *fmt,...)
Definition: elog.c:822
#define elog(elevel,...)
Definition: elog.h:228
int i
#define SGITHDRSZ
#define IndexTupleSize(itup)
Definition: itup.h:71

◆ spgFormLeafTuple()

SpGistLeafTuple spgFormLeafTuple ( SpGistState state,
ItemPointer  heapPtr,
Datum  datum,
bool  isnull 
)

Definition at line 647 of file spgutils.c.

References SpGistState::attLeafType, SpGistLeafTupleData::heapPtr, InvalidOffsetNumber, memcpyDatum(), SpGistLeafTupleData::nextOffset, palloc0(), SGDTSIZE, SGLTDATAPTR, SGLTHDRSZ, SpGistLeafTupleData::size, and SpGistGetTypeSize().

Referenced by doPickSplit(), and spgdoinsert().

649 {
650  SpGistLeafTuple tup;
651  unsigned int size;
652 
653  /* compute space needed (note result is already maxaligned) */
654  size = SGLTHDRSZ;
655  if (!isnull)
656  size += SpGistGetTypeSize(&state->attLeafType, datum);
657 
658  /*
659  * Ensure that we can replace the tuple with a dead tuple later. This
660  * test is unnecessary when !isnull, but let's be safe.
661  */
662  if (size < SGDTSIZE)
663  size = SGDTSIZE;
664 
665  /* OK, form the tuple */
666  tup = (SpGistLeafTuple) palloc0(size);
667 
668  tup->size = size;
670  tup->heapPtr = *heapPtr;
671  if (!isnull)
672  memcpyDatum(SGLTDATAPTR(tup), &state->attLeafType, datum);
673 
674  return tup;
675 }
#define SGDTSIZE
SpGistTypeDesc attLeafType
#define SGLTDATAPTR(x)
#define SGLTHDRSZ
unsigned int SpGistGetTypeSize(SpGistTypeDesc *att, Datum datum)
Definition: spgutils.c:610
void * palloc0(Size size)
Definition: mcxt.c:980
#define InvalidOffsetNumber
Definition: off.h:26
OffsetNumber nextOffset
static void memcpyDatum(void *target, SpGistTypeDesc *att, Datum datum)
Definition: spgutils.c:628
ItemPointerData heapPtr
SpGistLeafTupleData * SpGistLeafTuple

◆ spgFormNodeTuple()

SpGistNodeTuple spgFormNodeTuple ( SpGistState state,
Datum  label,
bool  isnull 
)

Definition at line 684 of file spgutils.c.

References SpGistState::attLabelType, ereport, errcode(), errmsg(), ERROR, INDEX_NULL_MASK, INDEX_SIZE_MASK, ItemPointerSetInvalid, memcpyDatum(), palloc0(), SGNTDATAPTR, SGNTHDRSZ, SpGistGetTypeSize(), IndexTupleData::t_info, and IndexTupleData::t_tid.

Referenced by addNode(), doPickSplit(), and spgSplitNodeAction().

685 {
686  SpGistNodeTuple tup;
687  unsigned int size;
688  unsigned short infomask = 0;
689 
690  /* compute space needed (note result is already maxaligned) */
691  size = SGNTHDRSZ;
692  if (!isnull)
693  size += SpGistGetTypeSize(&state->attLabelType, label);
694 
695  /*
696  * Here we make sure that the size will fit in the field reserved for it
697  * in t_info.
698  */
699  if ((size & INDEX_SIZE_MASK) != size)
700  ereport(ERROR,
701  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
702  errmsg("index row requires %zu bytes, maximum size is %zu",
703  (Size) size, (Size) INDEX_SIZE_MASK)));
704 
705  tup = (SpGistNodeTuple) palloc0(size);
706 
707  if (isnull)
708  infomask |= INDEX_NULL_MASK;
709  /* we don't bother setting the INDEX_VAR_MASK bit */
710  infomask |= size;
711  tup->t_info = infomask;
712 
713  /* The TID field will be filled in later */
715 
716  if (!isnull)
717  memcpyDatum(SGNTDATAPTR(tup), &state->attLabelType, label);
718 
719  return tup;
720 }
ItemPointerData t_tid
Definition: itup.h:37
#define INDEX_SIZE_MASK
Definition: itup.h:65
int errcode(int sqlerrcode)
Definition: elog.c:608
SpGistTypeDesc attLabelType
#define SGNTHDRSZ
#define ERROR
Definition: elog.h:43
#define INDEX_NULL_MASK
Definition: itup.h:69
#define ereport(elevel, rest)
Definition: elog.h:141
unsigned int SpGistGetTypeSize(SpGistTypeDesc *att, Datum datum)
Definition: spgutils.c:610
void * palloc0(Size size)
Definition: mcxt.c:980
static char * label
#define SGNTDATAPTR(x)
size_t Size
Definition: c.h:467
#define ItemPointerSetInvalid(pointer)
Definition: itemptr.h:172
static void memcpyDatum(void *target, SpGistTypeDesc *att, Datum datum)
Definition: spgutils.c:628
int errmsg(const char *fmt,...)
Definition: elog.c:822
unsigned short t_info
Definition: itup.h:49
SpGistNodeTupleData * SpGistNodeTuple

◆ spgGetCache()

SpGistCache* spgGetCache ( Relation  index)

Definition at line 103 of file spgutils.c.

References Assert, SpGistCache::attLabelType, SpGistCache::attLeafType, SpGistCache::attPrefixType, spgConfigIn::attType, SpGistCache::attType, BUFFER_LOCK_SHARE, BufferGetPage, SpGistCache::config, elog, ereport, errcode(), errmsg(), ERROR, fillTypeDesc(), FunctionCall2Coll(), index_getprocid(), index_getprocinfo(), spgConfigOut::labelType, SpGistMetaPageData::lastUsedPages, SpGistCache::lastUsedPages, spgConfigOut::leafType, LockBuffer(), SpGistMetaPageData::magicNumber, MemoryContextAllocZero(), TupleDescData::natts, OidIsValid, PointerGetDatum, spgConfigOut::prefixType, RelationData::rd_amcache, RelationData::rd_att, RelationData::rd_indcollation, RelationData::rd_indexcxt, ReadBuffer(), RelationGetRelationName, SPGIST_COMPRESS_PROC, SPGIST_CONFIG_PROC, SPGIST_MAGIC_NUMBER, SPGIST_METAPAGE_BLKNO, SpGistPageGetMeta, TupleDescAttr, and UnlockReleaseBuffer().

Referenced by allocNewBuffer(), initSpGistState(), spgcanreturn(), SpGistGetBuffer(), and SpGistSetLastUsedPage().

104 {
105  SpGistCache *cache;
106 
107  if (index->rd_amcache == NULL)
108  {
109  Oid atttype;
110  spgConfigIn in;
111  FmgrInfo *procinfo;
112  Buffer metabuffer;
113  SpGistMetaPageData *metadata;
114 
115  cache = MemoryContextAllocZero(index->rd_indexcxt,
116  sizeof(SpGistCache));
117 
118  /* SPGiST doesn't support multi-column indexes */
119  Assert(index->rd_att->natts == 1);
120 
121  /*
122  * Get the actual data type of the indexed column from the index
123  * tupdesc. We pass this to the opclass config function so that
124  * polymorphic opclasses are possible.
125  */
126  atttype = TupleDescAttr(index->rd_att, 0)->atttypid;
127 
128  /* Call the config function to get config info for the opclass */
129  in.attType = atttype;
130 
131  procinfo = index_getprocinfo(index, 1, SPGIST_CONFIG_PROC);
132  FunctionCall2Coll(procinfo,
133  index->rd_indcollation[0],
134  PointerGetDatum(&in),
135  PointerGetDatum(&cache->config));
136 
137  /* Get the information we need about each relevant datatype */
138  fillTypeDesc(&cache->attType, atttype);
139 
140  if (OidIsValid(cache->config.leafType) &&
141  cache->config.leafType != atttype)
142  {
144  ereport(ERROR,
145  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
146  errmsg("compress method must be defined when leaf type is different from input type")));
147 
148  fillTypeDesc(&cache->attLeafType, cache->config.leafType);
149  }
150  else
151  {
152  cache->attLeafType = cache->attType;
153  }
154 
155  fillTypeDesc(&cache->attPrefixType, cache->config.prefixType);
156  fillTypeDesc(&cache->attLabelType, cache->config.labelType);
157 
158  /* Last, get the lastUsedPages data from the metapage */
159  metabuffer = ReadBuffer(index, SPGIST_METAPAGE_BLKNO);
160  LockBuffer(metabuffer, BUFFER_LOCK_SHARE);
161 
162  metadata = SpGistPageGetMeta(BufferGetPage(metabuffer));
163 
164  if (metadata->magicNumber != SPGIST_MAGIC_NUMBER)
165  elog(ERROR, "index \"%s\" is not an SP-GiST index",
166  RelationGetRelationName(index));
167 
168  cache->lastUsedPages = metadata->lastUsedPages;
169 
170  UnlockReleaseBuffer(metabuffer);
171 
172  index->rd_amcache = (void *) cache;
173  }
174  else
175  {
176  /* assume it's up to date */
177  cache = (SpGistCache *) index->rd_amcache;
178  }
179 
180  return cache;
181 }
SpGistTypeDesc attLeafType
Definition: fmgr.h:56
FmgrInfo * index_getprocinfo(Relation irel, AttrNumber attnum, uint16 procnum)
Definition: indexam.c:794
#define PointerGetDatum(X)
Definition: postgres.h:556
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
int errcode(int sqlerrcode)
Definition: elog.c:608
Oid attType
Definition: spgist.h:37
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1150
unsigned int Oid
Definition: postgres_ext.h:31
SpGistTypeDesc attType
#define OidIsValid(objectId)
Definition: c.h:645
SpGistLUPCache lastUsedPages
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3398
Oid * rd_indcollation
Definition: rel.h:174
#define ERROR
Definition: elog.h:43
#define SPGIST_METAPAGE_BLKNO
#define RelationGetRelationName(relation)
Definition: rel.h:462
#define BufferGetPage(buffer)
Definition: bufmgr.h:159
#define ereport(elevel, rest)
Definition: elog.h:141
#define SPGIST_MAGIC_NUMBER
spgConfigOut config
SpGistLUPCache lastUsedPages
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3612
Oid prefixType
Definition: spgist.h:42
TupleDesc rd_att
Definition: rel.h:85
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:839
#define Assert(condition)
Definition: c.h:739
#define SPGIST_COMPRESS_PROC
Definition: spgist.h:28
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:596
#define SPGIST_CONFIG_PROC
Definition: spgist.h:23
#define SpGistPageGetMeta(p)
SpGistTypeDesc attLabelType
int errmsg(const char *fmt,...)
Definition: elog.c:822
#define elog(elevel,...)
Definition: elog.h:228
MemoryContext rd_indexcxt
Definition: rel.h:161
Oid labelType
Definition: spgist.h:43
Oid leafType
Definition: spgist.h:44
#define BUFFER_LOCK_SHARE
Definition: bufmgr.h:87
SpGistTypeDesc attPrefixType
static void fillTypeDesc(SpGistTypeDesc *desc, Oid type)
Definition: spgutils.c:92
void * rd_amcache
Definition: rel.h:185
int Buffer
Definition: buf.h:23
RegProcedure index_getprocid(Relation irel, AttrNumber attnum, uint16 procnum)
Definition: indexam.c:760

◆ spghandler()

Datum spghandler ( PG_FUNCTION_ARGS  )

Definition at line 41 of file spgutils.c.

References IndexAmRoutine::ambeginscan, IndexAmRoutine::ambuild, IndexAmRoutine::ambuildempty, IndexAmRoutine::ambuildphasename, IndexAmRoutine::ambulkdelete, IndexAmRoutine::amcanbackward, IndexAmRoutine::amcaninclude, IndexAmRoutine::amcanmulticol, IndexAmRoutine::amcanorder, IndexAmRoutine::amcanorderbyop, IndexAmRoutine::amcanparallel, IndexAmRoutine::amcanreturn, IndexAmRoutine::amcanunique, IndexAmRoutine::amclusterable, IndexAmRoutine::amcostestimate, IndexAmRoutine::amendscan, IndexAmRoutine::amestimateparallelscan, IndexAmRoutine::amgetbitmap, IndexAmRoutine::amgettuple, IndexAmRoutine::aminitparallelscan, IndexAmRoutine::aminsert, IndexAmRoutine::amkeytype, IndexAmRoutine::ammarkpos, IndexAmRoutine::amoptionalkey, IndexAmRoutine::amoptions, IndexAmRoutine::amparallelrescan, IndexAmRoutine::amparallelvacuumoptions, IndexAmRoutine::ampredlocks, IndexAmRoutine::amproperty, IndexAmRoutine::amrescan, IndexAmRoutine::amrestrpos, IndexAmRoutine::amsearcharray, IndexAmRoutine::amsearchnulls, IndexAmRoutine::amstorage, IndexAmRoutine::amstrategies, IndexAmRoutine::amsupport, IndexAmRoutine::amusemaintenanceworkmem, IndexAmRoutine::amvacuumcleanup, IndexAmRoutine::amvalidate, InvalidOid, makeNode, PG_RETURN_POINTER, spgbeginscan(), spgbuild(), spgbuildempty(), spgbulkdelete(), spgcanreturn(), spgcostestimate(), spgendscan(), spggetbitmap(), spggettuple(), spginsert(), SPGISTNProc, spgoptions(), spgproperty(), spgrescan(), spgvacuumcleanup(), spgvalidate(), VACUUM_OPTION_PARALLEL_BULKDEL, and VACUUM_OPTION_PARALLEL_COND_CLEANUP.

42 {
44 
45  amroutine->amstrategies = 0;
46  amroutine->amsupport = SPGISTNProc;
47  amroutine->amcanorder = false;
48  amroutine->amcanorderbyop = true;
49  amroutine->amcanbackward = false;
50  amroutine->amcanunique = false;
51  amroutine->amcanmulticol = false;
52  amroutine->amoptionalkey = true;
53  amroutine->amsearcharray = false;
54  amroutine->amsearchnulls = true;
55  amroutine->amstorage = false;
56  amroutine->amclusterable = false;
57  amroutine->ampredlocks = false;
58  amroutine->amcanparallel = false;
59  amroutine->amcaninclude = false;
60  amroutine->amusemaintenanceworkmem = false;
61  amroutine->amparallelvacuumoptions =
63  amroutine->amkeytype = InvalidOid;
64 
65  amroutine->ambuild = spgbuild;
66  amroutine->ambuildempty = spgbuildempty;
67  amroutine->aminsert = spginsert;
68  amroutine->ambulkdelete = spgbulkdelete;
69  amroutine->amvacuumcleanup = spgvacuumcleanup;
70  amroutine->amcanreturn = spgcanreturn;
71  amroutine->amcostestimate = spgcostestimate;
72  amroutine->amoptions = spgoptions;
73  amroutine->amproperty = spgproperty;
74  amroutine->ambuildphasename = NULL;
75  amroutine->amvalidate = spgvalidate;
76  amroutine->ambeginscan = spgbeginscan;
77  amroutine->amrescan = spgrescan;
78  amroutine->amgettuple = spggettuple;
79  amroutine->amgetbitmap = spggetbitmap;
80  amroutine->amendscan = spgendscan;
81  amroutine->ammarkpos = NULL;
82  amroutine->amrestrpos = NULL;
83  amroutine->amestimateparallelscan = NULL;
84  amroutine->aminitparallelscan = NULL;
85  amroutine->amparallelrescan = NULL;
86 
87  PG_RETURN_POINTER(amroutine);
88 }
ambeginscan_function ambeginscan
Definition: amapi.h:225
uint8 amparallelvacuumoptions
Definition: amapi.h:203
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:351
ambulkdelete_function ambulkdelete
Definition: amapi.h:217
bool amcanmulticol
Definition: amapi.h:183
uint16 amsupport
Definition: amapi.h:173
amgettuple_function amgettuple
Definition: amapi.h:227
bool amcanorderbyop
Definition: amapi.h:177
amproperty_function amproperty
Definition: amapi.h:222
bool spgproperty(Oid index_oid, int attno, IndexAMProperty prop, const char *propname, bool *res, bool *isnull)
Definition: spgutils.c:977
IndexBulkDeleteResult * spgvacuumcleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats)
Definition: spgvacuum.c:932
amparallelrescan_function amparallelrescan
Definition: amapi.h:236
bool amstorage
Definition: amapi.h:191
void spgrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys, ScanKey orderbys, int norderbys)
Definition: spgscan.c:365
bool ampredlocks
Definition: amapi.h:195
aminsert_function aminsert
Definition: amapi.h:216
bool spginsert(Relation index, Datum *values, bool *isnull, ItemPointer ht_ctid, Relation heapRel, IndexUniqueCheck checkUnique, IndexInfo *indexInfo)
Definition: spginsert.c:207
Oid amkeytype
Definition: amapi.h:205
void spgendscan(IndexScanDesc scan)
Definition: spgscan.c:411
bool amoptionalkey
Definition: amapi.h:185
amvalidate_function amvalidate
Definition: amapi.h:224
bool spgcanreturn(Relation index, int attno)
Definition: spgscan.c:1019
amgetbitmap_function amgetbitmap
Definition: amapi.h:228
IndexBulkDeleteResult * spgbulkdelete(IndexVacuumInfo *info, IndexBulkDeleteResult *stats, IndexBulkDeleteCallback callback, void *callback_state)
Definition: spgvacuum.c:901
ambuild_function ambuild
Definition: amapi.h:214
amoptions_function amoptions
Definition: amapi.h:221
bool amcaninclude
Definition: amapi.h:199
amcostestimate_function amcostestimate
Definition: amapi.h:220
bool amcanunique
Definition: amapi.h:181
amvacuumcleanup_function amvacuumcleanup
Definition: amapi.h:218
amendscan_function amendscan
Definition: amapi.h:229
bool amcanbackward
Definition: amapi.h:179
int64 spggetbitmap(IndexScanDesc scan, TIDBitmap *tbm)
Definition: spgscan.c:889
void spgbuildempty(Relation index)
Definition: spginsert.c:156
amrescan_function amrescan
Definition: amapi.h:226
bool amcanparallel
Definition: amapi.h:197
bytea * spgoptions(Datum reloptions, bool validate)
Definition: spgutils.c:590
bool amsearchnulls
Definition: amapi.h:189
bool amclusterable
Definition: amapi.h:193
bool amsearcharray
Definition: amapi.h:187
#define InvalidOid
Definition: postgres_ext.h:36
bool amusemaintenanceworkmem
Definition: amapi.h:201
void spgcostestimate(PlannerInfo *root, IndexPath *path, double loop_count, Cost *indexStartupCost, Cost *indexTotalCost, Selectivity *indexSelectivity, double *indexCorrelation, double *indexPages)
Definition: selfuncs.c:6296
#define makeNode(_type_)
Definition: nodes.h:573
#define VACUUM_OPTION_PARALLEL_COND_CLEANUP
Definition: vacuum.h:52
ammarkpos_function ammarkpos
Definition: amapi.h:230
bool amcanorder
Definition: amapi.h:175
ambuildphasename_function ambuildphasename
Definition: amapi.h:223
#define VACUUM_OPTION_PARALLEL_BULKDEL
Definition: vacuum.h:45
amestimateparallelscan_function amestimateparallelscan
Definition: amapi.h:234
IndexBuildResult * spgbuild(Relation heap, Relation index, IndexInfo *indexInfo)
Definition: spginsert.c:75
uint16 amstrategies
Definition: amapi.h:171
#define SPGISTNProc
Definition: spgist.h:30
bool spgvalidate(Oid opclassoid)
Definition: spgvalidate.c:39
bool spggettuple(IndexScanDesc scan, ScanDirection dir)
Definition: spgscan.c:961
ambuildempty_function ambuildempty
Definition: amapi.h:215
IndexScanDesc spgbeginscan(Relation rel, int keysz, int orderbysz)
Definition: spgscan.c:295
amcanreturn_function amcanreturn
Definition: amapi.h:219
aminitparallelscan_function aminitparallelscan
Definition: amapi.h:235
amrestrpos_function amrestrpos
Definition: amapi.h:231

◆ SpGistGetBuffer()

Buffer SpGistGetBuffer ( Relation  index,
int  flags,
int  needSpace,
bool isNew 
)

Definition at line 399 of file spgutils.c.

References allocNewBuffer(), Assert, SpGistLastUsedPage::blkno, BufferGetPage, ConditionalLockBuffer(), elog, ERROR, SpGistLastUsedPage::freeSpace, GBUF_REQ_LEAF, GBUF_REQ_NULLS, GET_LUP, InvalidBlockNumber, Min, PageGetExactFreeSpace(), PageIsEmpty, PageIsNew, ReadBuffer(), ReleaseBuffer(), spgGetCache(), SPGIST_LEAF, SPGIST_NULLS, SPGIST_PAGE_CAPACITY, SpGistBlockIsFixed, SpGistGetTargetPageFreeSpace, SpGistInitBuffer(), SpGistPageIsDeleted, SpGistPageIsLeaf, SpGistPageStoresNulls, and UnlockReleaseBuffer().

Referenced by doPickSplit(), moveLeafs(), spgAddNodeAction(), spgdoinsert(), and spgSplitNodeAction().

400 {
401  SpGistCache *cache = spgGetCache(index);
402  SpGistLastUsedPage *lup;
403 
404  /* Bail out if even an empty page wouldn't meet the demand */
405  if (needSpace > SPGIST_PAGE_CAPACITY)
406  elog(ERROR, "desired SPGiST tuple size is too big");
407 
408  /*
409  * If possible, increase the space request to include relation's
410  * fillfactor. This ensures that when we add unrelated tuples to a page,
411  * we try to keep 100-fillfactor% available for adding tuples that are
412  * related to the ones already on it. But fillfactor mustn't cause an
413  * error for requests that would otherwise be legal.
414  */
415  needSpace += SpGistGetTargetPageFreeSpace(index);
416  needSpace = Min(needSpace, SPGIST_PAGE_CAPACITY);
417 
418  /* Get the cache entry for this flags setting */
419  lup = GET_LUP(cache, flags);
420 
421  /* If we have nothing cached, just turn it over to allocNewBuffer */
422  if (lup->blkno == InvalidBlockNumber)
423  {
424  *isNew = true;
425  return allocNewBuffer(index, flags);
426  }
427 
428  /* fixed pages should never be in cache */
430 
431  /* If cached freeSpace isn't enough, don't bother looking at the page */
432  if (lup->freeSpace >= needSpace)
433  {
434  Buffer buffer;
435  Page page;
436 
437  buffer = ReadBuffer(index, lup->blkno);
438 
439  if (!ConditionalLockBuffer(buffer))
440  {
441  /*
442  * buffer is locked by another process, so return a new buffer
443  */
444  ReleaseBuffer(buffer);
445  *isNew = true;
446  return allocNewBuffer(index, flags);
447  }
448 
449  page = BufferGetPage(buffer);
450 
451  if (PageIsNew(page) || SpGistPageIsDeleted(page) || PageIsEmpty(page))
452  {
453  /* OK to initialize the page */
454  uint16 pageflags = 0;
455 
456  if (GBUF_REQ_LEAF(flags))
457  pageflags |= SPGIST_LEAF;
458  if (GBUF_REQ_NULLS(flags))
459  pageflags |= SPGIST_NULLS;
460  SpGistInitBuffer(buffer, pageflags);
461  lup->freeSpace = PageGetExactFreeSpace(page) - needSpace;
462  *isNew = true;
463  return buffer;
464  }
465 
466  /*
467  * Check that page is of right type and has enough space. We must
468  * recheck this since our cache isn't necessarily up to date.
469  */
470  if ((GBUF_REQ_LEAF(flags) ? SpGistPageIsLeaf(page) : !SpGistPageIsLeaf(page)) &&
472  {
473  int freeSpace = PageGetExactFreeSpace(page);
474 
475  if (freeSpace >= needSpace)
476  {
477  /* Success, update freespace info and return the buffer */
478  lup->freeSpace = freeSpace - needSpace;
479  *isNew = false;
480  return buffer;
481  }
482  }
483 
484  /*
485  * fallback to allocation of new buffer
486  */
487  UnlockReleaseBuffer(buffer);
488  }
489 
490  /* No success with cache, so return a new buffer */
491  *isNew = true;
492  return allocNewBuffer(index, flags);
493 }
#define PageIsEmpty(page)
Definition: bufpage.h:222
#define SpGistPageIsLeaf(page)
SpGistCache * spgGetCache(Relation index)
Definition: spgutils.c:103
#define GET_LUP(c, f)
Definition: spgutils.c:320
#define Min(x, y)
Definition: c.h:911
#define SPGIST_NULLS
static Buffer allocNewBuffer(Relation index, int flags)
Definition: spgutils.c:343
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3375
#define GBUF_REQ_NULLS(flags)
unsigned short uint16
Definition: c.h:358
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3398
#define ERROR
Definition: elog.h:43
#define SpGistBlockIsFixed(blkno)
void SpGistInitBuffer(Buffer b, uint16 f)
Definition: spgutils.c:553
#define BufferGetPage(buffer)
Definition: bufmgr.h:159
bool ConditionalLockBuffer(Buffer buffer)
Definition: bufmgr.c:3638
#define SPGIST_PAGE_CAPACITY
#define SpGistPageStoresNulls(page)
#define Assert(condition)
Definition: c.h:739
#define SpGistPageIsDeleted(page)
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:596
#define InvalidBlockNumber
Definition: block.h:33
Size PageGetExactFreeSpace(Page page)
Definition: bufpage.c:632
#define PageIsNew(page)
Definition: bufpage.h:229
#define elog(elevel,...)
Definition: elog.h:228
#define SpGistGetTargetPageFreeSpace(relation)
#define SPGIST_LEAF
int Buffer
Definition: buf.h:23
Pointer Page
Definition: bufpage.h:78
#define GBUF_REQ_LEAF(flags)

◆ SpGistGetTypeSize()

unsigned int SpGistGetTypeSize ( SpGistTypeDesc att,
Datum  datum 
)

Definition at line 610 of file spgutils.c.

References SpGistTypeDesc::attbyval, SpGistTypeDesc::attlen, MAXALIGN, and VARSIZE_ANY.

Referenced by spgdoinsert(), spgFormInnerTuple(), spgFormLeafTuple(), and spgFormNodeTuple().

611 {
612  unsigned int size;
613 
614  if (att->attbyval)
615  size = sizeof(Datum);
616  else if (att->attlen > 0)
617  size = att->attlen;
618  else
619  size = VARSIZE_ANY(datum);
620 
621  return MAXALIGN(size);
622 }
uintptr_t Datum
Definition: postgres.h:367
#define VARSIZE_ANY(PTR)
Definition: postgres.h:335
#define MAXALIGN(LEN)
Definition: c.h:692

◆ SpGistInitBuffer()

void SpGistInitBuffer ( Buffer  b,
uint16  f 
)

Definition at line 553 of file spgutils.c.

References Assert, BufferGetPage, BufferGetPageSize, and SpGistInitPage().

Referenced by allocNewBuffer(), doPickSplit(), spgbuild(), SpGistGetBuffer(), spgRedoAddLeaf(), spgRedoAddNode(), spgRedoMoveLeafs(), spgRedoPickSplit(), and spgRedoSplitTuple().

554 {
555  Assert(BufferGetPageSize(b) == BLCKSZ);
557 }
#define BufferGetPage(buffer)
Definition: bufmgr.h:159
#define BufferGetPageSize(buffer)
Definition: bufmgr.h:146
#define Assert(condition)
Definition: c.h:739
void SpGistInitPage(Page page, uint16 f)
Definition: spgutils.c:538

◆ SpGistInitMetapage()

void SpGistInitMetapage ( Page  page)

Definition at line 563 of file spgutils.c.

References SpGistLastUsedPage::blkno, SpGistLUPCache::cachedPage, i, InvalidBlockNumber, SpGistMetaPageData::lastUsedPages, SpGistMetaPageData::magicNumber, SPGIST_CACHED_PAGES, SPGIST_MAGIC_NUMBER, SPGIST_META, SpGistInitPage(), and SpGistPageGetMeta.

Referenced by spgbuild(), and spgbuildempty().

564 {
565  SpGistMetaPageData *metadata;
566  int i;
567 
569  metadata = SpGistPageGetMeta(page);
570  memset(metadata, 0, sizeof(SpGistMetaPageData));
571  metadata->magicNumber = SPGIST_MAGIC_NUMBER;
572 
573  /* initialize last-used-page cache to empty */
574  for (i = 0; i < SPGIST_CACHED_PAGES; i++)
576 
577  /*
578  * Set pd_lower just past the end of the metadata. This is essential,
579  * because without doing so, metadata will be lost if xlog.c compresses
580  * the page.
581  */
582  ((PageHeader) page)->pd_lower =
583  ((char *) metadata + sizeof(SpGistMetaPageData)) - (char *) page;
584 }
SpGistLastUsedPage cachedPage[SPGIST_CACHED_PAGES]
#define SPGIST_META
#define SPGIST_MAGIC_NUMBER
SpGistLUPCache lastUsedPages
#define InvalidBlockNumber
Definition: block.h:33
#define SPGIST_CACHED_PAGES
#define SpGistPageGetMeta(p)
void SpGistInitPage(Page page, uint16 f)
Definition: spgutils.c:538
int i

◆ SpGistInitPage()

void SpGistInitPage ( Page  page,
uint16  f 
)

Definition at line 538 of file spgutils.c.

References SpGistPageOpaqueData::flags, MAXALIGN, PageInit(), SpGistPageOpaqueData::spgist_page_id, SPGIST_PAGE_ID, and SpGistPageGetOpaque.

Referenced by spgbuildempty(), SpGistInitBuffer(), and SpGistInitMetapage().

539 {
540  SpGistPageOpaque opaque;
541 
542  PageInit(page, BLCKSZ, MAXALIGN(sizeof(SpGistPageOpaqueData)));
543  opaque = SpGistPageGetOpaque(page);
544  memset(opaque, 0, sizeof(SpGistPageOpaqueData));
545  opaque->flags = f;
546  opaque->spgist_page_id = SPGIST_PAGE_ID;
547 }
#define SPGIST_PAGE_ID
#define MAXALIGN(LEN)
Definition: c.h:692
#define SpGistPageGetOpaque(page)
void PageInit(Page page, Size pageSize, Size specialSize)
Definition: bufpage.c:42

◆ SpGistNewBuffer()

Buffer SpGistNewBuffer ( Relation  index)

Definition at line 215 of file spgutils.c.

References BUFFER_LOCK_EXCLUSIVE, BUFFER_LOCK_UNLOCK, BufferGetPage, ConditionalLockBuffer(), ExclusiveLock, GetFreeIndexPage(), InvalidBlockNumber, LockBuffer(), LockRelationForExtension(), P_NEW, PageIsEmpty, PageIsNew, ReadBuffer(), RELATION_IS_LOCAL, ReleaseBuffer(), SpGistBlockIsFixed, SpGistPageIsDeleted, and UnlockRelationForExtension().

Referenced by allocNewBuffer(), and spgbuild().

216 {
217  Buffer buffer;
218  bool needLock;
219 
220  /* First, try to get a page from FSM */
221  for (;;)
222  {
223  BlockNumber blkno = GetFreeIndexPage(index);
224 
225  if (blkno == InvalidBlockNumber)
226  break; /* nothing known to FSM */
227 
228  /*
229  * The fixed pages shouldn't ever be listed in FSM, but just in case
230  * one is, ignore it.
231  */
232  if (SpGistBlockIsFixed(blkno))
233  continue;
234 
235  buffer = ReadBuffer(index, blkno);
236 
237  /*
238  * We have to guard against the possibility that someone else already
239  * recycled this page; the buffer may be locked if so.
240  */
241  if (ConditionalLockBuffer(buffer))
242  {
243  Page page = BufferGetPage(buffer);
244 
245  if (PageIsNew(page))
246  return buffer; /* OK to use, if never initialized */
247 
248  if (SpGistPageIsDeleted(page) || PageIsEmpty(page))
249  return buffer; /* OK to use */
250 
252  }
253 
254  /* Can't use it, so release buffer and try again */
255  ReleaseBuffer(buffer);
256  }
257 
258  /* Must extend the file */
259  needLock = !RELATION_IS_LOCAL(index);
260  if (needLock)
262 
263  buffer = ReadBuffer(index, P_NEW);
265 
266  if (needLock)
268 
269  return buffer;
270 }
#define BUFFER_LOCK_UNLOCK
Definition: bufmgr.h:86
#define PageIsEmpty(page)
Definition: bufpage.h:222
#define ExclusiveLock
Definition: lockdefs.h:44
#define RELATION_IS_LOCAL(relation)
Definition: rel.h:548
uint32 BlockNumber
Definition: block.h:31
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3375
#define P_NEW
Definition: bufmgr.h:81
#define BUFFER_LOCK_EXCLUSIVE
Definition: bufmgr.h:88
#define SpGistBlockIsFixed(blkno)
#define BufferGetPage(buffer)
Definition: bufmgr.h:159
bool ConditionalLockBuffer(Buffer buffer)
Definition: bufmgr.c:3638
void LockRelationForExtension(Relation relation, LOCKMODE lockmode)
Definition: lmgr.c:402
void UnlockRelationForExtension(Relation relation, LOCKMODE lockmode)
Definition: lmgr.c:452
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3612
BlockNumber GetFreeIndexPage(Relation rel)
Definition: indexfsm.c:38
#define SpGistPageIsDeleted(page)
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:596
#define InvalidBlockNumber
Definition: block.h:33
#define PageIsNew(page)
Definition: bufpage.h:229
int Buffer
Definition: buf.h:23
Pointer Page
Definition: bufpage.h:78

◆ SpGistPageAddNewItem()

OffsetNumber SpGistPageAddNewItem ( SpGistState state,
Page  page,
Item  item,
Size  size,
OffsetNumber startOffset,
bool  errorOK 
)

Definition at line 882 of file spgutils.c.

References Assert, elog, ERROR, FirstOffsetNumber, i, InvalidOffsetNumber, MAXALIGN, SpGistPageOpaqueData::nPlaceholder, PageAddItem, PageGetExactFreeSpace(), PageGetItem, PageGetItemId, PageGetMaxOffsetNumber, PageIndexTupleDelete(), PANIC, SGDTSIZE, SPGIST_PLACEHOLDER, SpGistPageGetOpaque, and SpGistDeadTupleData::tupstate.

Referenced by addLeafTuple(), doPickSplit(), moveLeafs(), spgAddNodeAction(), and spgSplitNodeAction().

884 {
885  SpGistPageOpaque opaque = SpGistPageGetOpaque(page);
886  OffsetNumber i,
887  maxoff,
888  offnum;
889 
890  if (opaque->nPlaceholder > 0 &&
891  PageGetExactFreeSpace(page) + SGDTSIZE >= MAXALIGN(size))
892  {
893  /* Try to replace a placeholder */
894  maxoff = PageGetMaxOffsetNumber(page);
895  offnum = InvalidOffsetNumber;
896 
897  for (;;)
898  {
899  if (startOffset && *startOffset != InvalidOffsetNumber)
900  i = *startOffset;
901  else
902  i = FirstOffsetNumber;
903  for (; i <= maxoff; i++)
904  {
906  PageGetItemId(page, i));
907 
908  if (it->tupstate == SPGIST_PLACEHOLDER)
909  {
910  offnum = i;
911  break;
912  }
913  }
914 
915  /* Done if we found a placeholder */
916  if (offnum != InvalidOffsetNumber)
917  break;
918 
919  if (startOffset && *startOffset != InvalidOffsetNumber)
920  {
921  /* Hint was no good, re-search from beginning */
922  *startOffset = InvalidOffsetNumber;
923  continue;
924  }
925 
926  /* Hmm, no placeholder found? */
927  opaque->nPlaceholder = 0;
928  break;
929  }
930 
931  if (offnum != InvalidOffsetNumber)
932  {
933  /* Replace the placeholder tuple */
934  PageIndexTupleDelete(page, offnum);
935 
936  offnum = PageAddItem(page, item, size, offnum, false, false);
937 
938  /*
939  * We should not have failed given the size check at the top of
940  * the function, but test anyway. If we did fail, we must PANIC
941  * because we've already deleted the placeholder tuple, and
942  * there's no other way to keep the damage from getting to disk.
943  */
944  if (offnum != InvalidOffsetNumber)
945  {
946  Assert(opaque->nPlaceholder > 0);
947  opaque->nPlaceholder--;
948  if (startOffset)
949  *startOffset = offnum + 1;
950  }
951  else
952  elog(PANIC, "failed to add item of size %u to SPGiST index page",
953  (int) size);
954 
955  return offnum;
956  }
957  }
958 
959  /* No luck in replacing a placeholder, so just add it to the page */
960  offnum = PageAddItem(page, item, size,
961  InvalidOffsetNumber, false, false);
962 
963  if (offnum == InvalidOffsetNumber && !errorOK)
964  elog(ERROR, "failed to add item of size %u to SPGiST index page",
965  (int) size);
966 
967  return offnum;
968 }
#define SGDTSIZE
void PageIndexTupleDelete(Page page, OffsetNumber offnum)
Definition: bufpage.c:726
#define SPGIST_PLACEHOLDER
#define PageAddItem(page, item, size, offsetNumber, overwrite, is_heap)
Definition: bufpage.h:416
#define PANIC
Definition: elog.h:53
#define PageGetMaxOffsetNumber(page)
Definition: bufpage.h:357
uint16 OffsetNumber
Definition: off.h:24
#define ERROR
Definition: elog.h:43
#define FirstOffsetNumber
Definition: off.h:27
SpGistDeadTupleData * SpGistDeadTuple
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:235
unsigned int tupstate
#define InvalidOffsetNumber
Definition: off.h:26
#define Assert(condition)
Definition: c.h:739
#define MAXALIGN(LEN)
Definition: c.h:692
Size PageGetExactFreeSpace(Page page)
Definition: bufpage.c:632
#define SpGistPageGetOpaque(page)
#define elog(elevel,...)
Definition: elog.h:228
int i
#define PageGetItem(page, itemId)
Definition: bufpage.h:340

◆ SpGistSetLastUsedPage()

void SpGistSetLastUsedPage ( Relation  index,
Buffer  buffer 
)

Definition at line 503 of file spgutils.c.

References SpGistLastUsedPage::blkno, BufferGetBlockNumber(), BufferGetPage, SpGistLastUsedPage::freeSpace, GBUF_INNER_PARITY, GBUF_LEAF, GBUF_NULLS, GET_LUP, InvalidBlockNumber, PageGetExactFreeSpace(), spgGetCache(), SpGistBlockIsFixed, SpGistPageIsLeaf, and SpGistPageStoresNulls.

Referenced by doPickSplit(), moveLeafs(), spgAddNodeAction(), spgdoinsert(), spgMatchNodeAction(), spgprocesspending(), spgSplitNodeAction(), and spgvacuumpage().

504 {
505  SpGistCache *cache = spgGetCache(index);
506  SpGistLastUsedPage *lup;
507  int freeSpace;
508  Page page = BufferGetPage(buffer);
509  BlockNumber blkno = BufferGetBlockNumber(buffer);
510  int flags;
511 
512  /* Never enter fixed pages (root pages) in cache, though */
513  if (SpGistBlockIsFixed(blkno))
514  return;
515 
516  if (SpGistPageIsLeaf(page))
517  flags = GBUF_LEAF;
518  else
519  flags = GBUF_INNER_PARITY(blkno);
520  if (SpGistPageStoresNulls(page))
521  flags |= GBUF_NULLS;
522 
523  lup = GET_LUP(cache, flags);
524 
525  freeSpace = PageGetExactFreeSpace(page);
526  if (lup->blkno == InvalidBlockNumber || lup->blkno == blkno ||
527  lup->freeSpace < freeSpace)
528  {
529  lup->blkno = blkno;
530  lup->freeSpace = freeSpace;
531  }
532 }
#define SpGistPageIsLeaf(page)
SpGistCache * spgGetCache(Relation index)
Definition: spgutils.c:103
#define GET_LUP(c, f)
Definition: spgutils.c:320
uint32 BlockNumber
Definition: block.h:31
#define GBUF_INNER_PARITY(x)
#define SpGistBlockIsFixed(blkno)
#define BufferGetPage(buffer)
Definition: bufmgr.h:159
#define GBUF_LEAF
#define SpGistPageStoresNulls(page)
#define InvalidBlockNumber
Definition: block.h:33
#define GBUF_NULLS
Size PageGetExactFreeSpace(Page page)
Definition: bufpage.c:632
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2623
Pointer Page
Definition: bufpage.h:78

◆ SpGistUpdateMetaPage()

void SpGistUpdateMetaPage ( Relation  index)

Definition at line 280 of file spgutils.c.

References BufferGetPage, ConditionalLockBuffer(), SpGistMetaPageData::lastUsedPages, SpGistCache::lastUsedPages, MarkBufferDirty(), RelationData::rd_amcache, ReadBuffer(), ReleaseBuffer(), SPGIST_METAPAGE_BLKNO, SpGistPageGetMeta, and UnlockReleaseBuffer().

Referenced by spgbuild(), spginsert(), and spgvacuumscan().

281 {
282  SpGistCache *cache = (SpGistCache *) index->rd_amcache;
283 
284  if (cache != NULL)
285  {
286  Buffer metabuffer;
287 
288  metabuffer = ReadBuffer(index, SPGIST_METAPAGE_BLKNO);
289 
290  if (ConditionalLockBuffer(metabuffer))
291  {
292  Page metapage = BufferGetPage(metabuffer);
293  SpGistMetaPageData *metadata = SpGistPageGetMeta(metapage);
294 
295  metadata->lastUsedPages = cache->lastUsedPages;
296 
297  /*
298  * Set pd_lower just past the end of the metadata. This is
299  * essential, because without doing so, metadata will be lost if
300  * xlog.c compresses the page. (We must do this here because
301  * pre-v11 versions of PG did not set the metapage's pd_lower
302  * correctly, so a pg_upgraded index might contain the wrong
303  * value.)
304  */
305  ((PageHeader) metapage)->pd_lower =
306  ((char *) metadata + sizeof(SpGistMetaPageData)) - (char *) metapage;
307 
308  MarkBufferDirty(metabuffer);
309  UnlockReleaseBuffer(metabuffer);
310  }
311  else
312  {
313  ReleaseBuffer(metabuffer);
314  }
315  }
316 }
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1458
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3375
SpGistLUPCache lastUsedPages
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3398
#define SPGIST_METAPAGE_BLKNO
#define BufferGetPage(buffer)
Definition: bufmgr.h:159
bool ConditionalLockBuffer(Buffer buffer)
Definition: bufmgr.c:3638
SpGistLUPCache lastUsedPages
PageHeaderData * PageHeader
Definition: bufpage.h:166
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:596
#define SpGistPageGetMeta(p)
void * rd_amcache
Definition: rel.h:185
int Buffer
Definition: buf.h:23
Pointer Page
Definition: bufpage.h:78

◆ spgoptions()

bytea* spgoptions ( Datum  reloptions,
bool  validate 
)

Definition at line 590 of file spgutils.c.

References build_reloptions(), fillfactor, lengthof, offsetof, RELOPT_KIND_SPGIST, and RELOPT_TYPE_INT.

Referenced by spghandler().

591 {
592  static const relopt_parse_elt tab[] = {
594  };
595 
596  return (bytea *) build_reloptions(reloptions, validate,
598  sizeof(SpGistOptions),
599  tab, lengthof(tab));
600 
601 }
#define lengthof(array)
Definition: c.h:669
void * build_reloptions(Datum reloptions, bool validate, relopt_kind kind, Size relopt_struct_size, const relopt_parse_elt *relopt_elems, int num_relopt_elems)
Definition: reloptions.c:1552
int fillfactor
Definition: pgbench.c:159
Definition: c.h:556
#define offsetof(type, field)
Definition: c.h:662

◆ spgproperty()

bool spgproperty ( Oid  index_oid,
int  attno,
IndexAMProperty  prop,
const char *  propname,
bool res,
bool isnull 
)

Definition at line 977 of file spgutils.c.

References AMOPSTRATEGY, AMPROP_DISTANCE_ORDERABLE, get_index_column_opclass(), get_op_rettype(), get_opclass_opfamily_and_input_type(), GETSTRUCT, i, catclist::members, catclist::n_members, ObjectIdGetDatum, OidIsValid, opfamily_can_sort_type(), ReleaseSysCacheList, SearchSysCacheList1, and catctup::tuple.

Referenced by spghandler().

980 {
981  Oid opclass,
982  opfamily,
983  opcintype;
984  CatCList *catlist;
985  int i;
986 
987  /* Only answer column-level inquiries */
988  if (attno == 0)
989  return false;
990 
991  switch (prop)
992  {
994  break;
995  default:
996  return false;
997  }
998 
999  /*
1000  * Currently, SP-GiST distance-ordered scans require that there be a
1001  * distance operator in the opclass with the default types. So we assume
1002  * that if such a operator exists, then there's a reason for it.
1003  */
1004 
1005  /* First we need to know the column's opclass. */
1006  opclass = get_index_column_opclass(index_oid, attno);
1007  if (!OidIsValid(opclass))
1008  {
1009  *isnull = true;
1010  return true;
1011  }
1012 
1013  /* Now look up the opclass family and input datatype. */
1014  if (!get_opclass_opfamily_and_input_type(opclass, &opfamily, &opcintype))
1015  {
1016  *isnull = true;
1017  return true;
1018  }
1019 
1020  /* And now we can check whether the operator is provided. */
1022  ObjectIdGetDatum(opfamily));
1023 
1024  *res = false;
1025 
1026  for (i = 0; i < catlist->n_members; i++)
1027  {
1028  HeapTuple amoptup = &catlist->members[i]->tuple;
1029  Form_pg_amop amopform = (Form_pg_amop) GETSTRUCT(amoptup);
1030 
1031  if (amopform->amoppurpose == AMOP_ORDER &&
1032  (amopform->amoplefttype == opcintype ||
1033  amopform->amoprighttype == opcintype) &&
1034  opfamily_can_sort_type(amopform->amopsortfamily,
1035  get_op_rettype(amopform->amopopr)))
1036  {
1037  *res = true;
1038  break;
1039  }
1040  }
1041 
1042  ReleaseSysCacheList(catlist);
1043 
1044  *isnull = false;
1045 
1046  return true;
1047 }
int n_members
Definition: catcache.h:176
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
bool opfamily_can_sort_type(Oid opfamilyoid, Oid datatypeoid)
Definition: amvalidate.c:217
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:645
Oid get_op_rettype(Oid opno)
Definition: lsyscache.c:1140
CatCTup * members[FLEXIBLE_ARRAY_MEMBER]
Definition: catcache.h:178
bool get_opclass_opfamily_and_input_type(Oid opclass, Oid *opfamily, Oid *opcintype)
Definition: lsyscache.c:1064
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define SearchSysCacheList1(cacheId, key1)
Definition: syscache.h:210
#define ReleaseSysCacheList(x)
Definition: syscache.h:217
Oid get_index_column_opclass(Oid index_oid, int attno)
Definition: lsyscache.c:3164
FormData_pg_amop * Form_pg_amop
Definition: pg_amop.h:88
int i
HeapTupleData tuple
Definition: catcache.h:121