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 322 of file spgutils.c.

Referenced by SpGistGetBuffer(), and SpGistSetLastUsedPage().

Function Documentation

◆ allocNewBuffer()

static Buffer allocNewBuffer ( Relation  index,
int  flags 
)
static

Definition at line 345 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().

346 {
347  SpGistCache *cache = spgGetCache(index);
348  uint16 pageflags = 0;
349 
350  if (GBUF_REQ_LEAF(flags))
351  pageflags |= SPGIST_LEAF;
352  if (GBUF_REQ_NULLS(flags))
353  pageflags |= SPGIST_NULLS;
354 
355  for (;;)
356  {
357  Buffer buffer;
358 
359  buffer = SpGistNewBuffer(index);
360  SpGistInitBuffer(buffer, pageflags);
361 
362  if (pageflags & SPGIST_LEAF)
363  {
364  /* Leaf pages have no parity concerns, so just use it */
365  return buffer;
366  }
367  else
368  {
369  BlockNumber blkno = BufferGetBlockNumber(buffer);
370  int blkFlags = GBUF_INNER_PARITY(blkno);
371 
372  if ((flags & GBUF_PARITY_MASK) == blkFlags)
373  {
374  /* Page has right parity, use it */
375  return buffer;
376  }
377  else
378  {
379  /* Page has wrong parity, record it in cache and try again */
380  if (pageflags & SPGIST_NULLS)
381  blkFlags |= GBUF_NULLS;
382  cache->lastUsedPages.cachedPage[blkFlags].blkno = blkno;
383  cache->lastUsedPages.cachedPage[blkFlags].freeSpace =
385  UnlockReleaseBuffer(buffer);
386  }
387  }
388  }
389 }
SpGistCache * spgGetCache(Relation index)
Definition: spgutils.c:105
#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:428
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3536
#define GBUF_INNER_PARITY(x)
void SpGistInitBuffer(Buffer b, uint16 f)
Definition: spgutils.c:555
#define BufferGetPage(buffer)
Definition: bufmgr.h:169
Buffer SpGistNewBuffer(Relation index)
Definition: spgutils.c:217
#define GBUF_PARITY_MASK
#define GBUF_NULLS
Size PageGetExactFreeSpace(Page page)
Definition: bufpage.c:841
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2663
#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 94 of file spgutils.c.

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

Referenced by spgGetCache().

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

◆ initSpGistState()

void initSpGistState ( SpGistState state,
Relation  index 
)

Definition at line 187 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().

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

◆ memcpyDatum()

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

Definition at line 630 of file spgutils.c.

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

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

631 {
632  unsigned int size;
633 
634  if (att->attbyval)
635  {
636  memcpy(target, &datum, sizeof(Datum));
637  }
638  else
639  {
640  size = (att->attlen > 0) ? att->attlen : VARSIZE_ANY(datum);
641  memcpy(target, DatumGetPointer(datum), size);
642  }
643 }
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 841 of file spgutils.c.

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

Referenced by spgdoinsert(), and spgInitInnerConsistentIn().

842 {
843  Datum *nodeLabels;
844  int i;
845  SpGistNodeTuple node;
846 
847  /* Either all the labels must be NULL, or none. */
848  node = SGITNODEPTR(innerTuple);
849  if (IndexTupleHasNulls(node))
850  {
851  SGITITERATE(innerTuple, i, node)
852  {
853  if (!IndexTupleHasNulls(node))
854  elog(ERROR, "some but not all node labels are null in SPGiST inner tuple");
855  }
856  /* They're all null, so just return NULL */
857  return NULL;
858  }
859  else
860  {
861  nodeLabels = (Datum *) palloc(sizeof(Datum) * innerTuple->nNodes);
862  SGITITERATE(innerTuple, i, node)
863  {
864  if (IndexTupleHasNulls(node))
865  elog(ERROR, "some but not all node labels are null in SPGiST inner tuple");
866  nodeLabels[i] = SGNTDATUM(node, state);
867  }
868  return nodeLabels;
869  }
870 }
#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:950
#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 811 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().

813 {
815 
816  tuple->tupstate = tupstate;
817  tuple->size = SGDTSIZE;
819 
820  if (tupstate == SPGIST_REDIRECT)
821  {
822  ItemPointerSet(&tuple->pointer, blkno, offnum);
824  tuple->xid = state->myXid;
825  }
826  else
827  {
829  tuple->xid = InvalidTransactionId;
830  }
831 
832  return tuple;
833 }
#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:800
#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 728 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().

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

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

◆ spgFormNodeTuple()

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

Definition at line 686 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().

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

◆ spgGetCache()

SpGistCache* spgGetCache ( Relation  index)

Definition at line 105 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().

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

◆ spghandler()

Datum spghandler ( PG_FUNCTION_ARGS  )

Definition at line 41 of file spgutils.c.

References IndexAmRoutine::amadjustmembers, 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::amoptsprocnum, 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, spgadjustmembers(), spgbeginscan(), spgbuild(), spgbuildempty(), spgbulkdelete(), spgcanreturn(), spgcostestimate(), spgendscan(), spggetbitmap(), spggettuple(), spginsert(), SPGIST_OPTIONS_PROC, 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;
48  amroutine->amcanorder = false;
49  amroutine->amcanorderbyop = true;
50  amroutine->amcanbackward = false;
51  amroutine->amcanunique = false;
52  amroutine->amcanmulticol = false;
53  amroutine->amoptionalkey = true;
54  amroutine->amsearcharray = false;
55  amroutine->amsearchnulls = true;
56  amroutine->amstorage = false;
57  amroutine->amclusterable = false;
58  amroutine->ampredlocks = false;
59  amroutine->amcanparallel = false;
60  amroutine->amcaninclude = false;
61  amroutine->amusemaintenanceworkmem = false;
62  amroutine->amparallelvacuumoptions =
64  amroutine->amkeytype = InvalidOid;
65 
66  amroutine->ambuild = spgbuild;
67  amroutine->ambuildempty = spgbuildempty;
68  amroutine->aminsert = spginsert;
69  amroutine->ambulkdelete = spgbulkdelete;
70  amroutine->amvacuumcleanup = spgvacuumcleanup;
71  amroutine->amcanreturn = spgcanreturn;
72  amroutine->amcostestimate = spgcostestimate;
73  amroutine->amoptions = spgoptions;
74  amroutine->amproperty = spgproperty;
75  amroutine->ambuildphasename = NULL;
76  amroutine->amvalidate = spgvalidate;
77  amroutine->amadjustmembers = spgadjustmembers;
78  amroutine->ambeginscan = spgbeginscan;
79  amroutine->amrescan = spgrescan;
80  amroutine->amgettuple = spggettuple;
81  amroutine->amgetbitmap = spggetbitmap;
82  amroutine->amendscan = spgendscan;
83  amroutine->ammarkpos = NULL;
84  amroutine->amrestrpos = NULL;
85  amroutine->amestimateparallelscan = NULL;
86  amroutine->aminitparallelscan = NULL;
87  amroutine->amparallelrescan = NULL;
88 
89  PG_RETURN_POINTER(amroutine);
90 }
ambeginscan_function ambeginscan
Definition: amapi.h:270
uint8 amparallelvacuumoptions
Definition: amapi.h:247
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:361
ambulkdelete_function ambulkdelete
Definition: amapi.h:261
bool amcanmulticol
Definition: amapi.h:227
uint16 amsupport
Definition: amapi.h:215
#define SPGIST_OPTIONS_PROC
Definition: spgist.h:29
amgettuple_function amgettuple
Definition: amapi.h:272
bool amcanorderbyop
Definition: amapi.h:221
amproperty_function amproperty
Definition: amapi.h:266
bool spgproperty(Oid index_oid, int attno, IndexAMProperty prop, const char *propname, bool *res, bool *isnull)
Definition: spgutils.c:979
IndexBulkDeleteResult * spgvacuumcleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats)
Definition: spgvacuum.c:936
amparallelrescan_function amparallelrescan
Definition: amapi.h:281
bool amstorage
Definition: amapi.h:235
void spgrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys, ScanKey orderbys, int norderbys)
Definition: spgscan.c:365
bool ampredlocks
Definition: amapi.h:239
aminsert_function aminsert
Definition: amapi.h:260
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:249
void spgendscan(IndexScanDesc scan)
Definition: spgscan.c:411
bool amoptionalkey
Definition: amapi.h:229
amvalidate_function amvalidate
Definition: amapi.h:268
bool spgcanreturn(Relation index, int attno)
Definition: spgscan.c:1018
amgetbitmap_function amgetbitmap
Definition: amapi.h:273
IndexBulkDeleteResult * spgbulkdelete(IndexVacuumInfo *info, IndexBulkDeleteResult *stats, IndexBulkDeleteCallback callback, void *callback_state)
Definition: spgvacuum.c:905
ambuild_function ambuild
Definition: amapi.h:258
amoptions_function amoptions
Definition: amapi.h:265
bool amcaninclude
Definition: amapi.h:243
amcostestimate_function amcostestimate
Definition: amapi.h:264
bool amcanunique
Definition: amapi.h:225
amvacuumcleanup_function amvacuumcleanup
Definition: amapi.h:262
amendscan_function amendscan
Definition: amapi.h:274
bool amcanbackward
Definition: amapi.h:223
void spgadjustmembers(Oid opfamilyoid, Oid opclassoid, List *operators, List *functions)
Definition: spgvalidate.c:311
int64 spggetbitmap(IndexScanDesc scan, TIDBitmap *tbm)
Definition: spgscan.c:888
void spgbuildempty(Relation index)
Definition: spginsert.c:156
amrescan_function amrescan
Definition: amapi.h:271
bool amcanparallel
Definition: amapi.h:241
bytea * spgoptions(Datum reloptions, bool validate)
Definition: spgutils.c:592
bool amsearchnulls
Definition: amapi.h:233
bool amclusterable
Definition: amapi.h:237
bool amsearcharray
Definition: amapi.h:231
#define InvalidOid
Definition: postgres_ext.h:36
bool amusemaintenanceworkmem
Definition: amapi.h:245
void spgcostestimate(PlannerInfo *root, IndexPath *path, double loop_count, Cost *indexStartupCost, Cost *indexTotalCost, Selectivity *indexSelectivity, double *indexCorrelation, double *indexPages)
Definition: selfuncs.c:6648
#define makeNode(_type_)
Definition: nodes.h:575
amadjustmembers_function amadjustmembers
Definition: amapi.h:269
#define VACUUM_OPTION_PARALLEL_COND_CLEANUP
Definition: vacuum.h:52
ammarkpos_function ammarkpos
Definition: amapi.h:275
bool amcanorder
Definition: amapi.h:219
ambuildphasename_function ambuildphasename
Definition: amapi.h:267
#define VACUUM_OPTION_PARALLEL_BULKDEL
Definition: vacuum.h:45
amestimateparallelscan_function amestimateparallelscan
Definition: amapi.h:279
IndexBuildResult * spgbuild(Relation heap, Relation index, IndexInfo *indexInfo)
Definition: spginsert.c:75
uint16 amstrategies
Definition: amapi.h:213
#define SPGISTNProc
Definition: spgist.h:31
bool spgvalidate(Oid opclassoid)
Definition: spgvalidate.c:39
uint16 amoptsprocnum
Definition: amapi.h:217
bool spggettuple(IndexScanDesc scan, ScanDirection dir)
Definition: spgscan.c:960
ambuildempty_function ambuildempty
Definition: amapi.h:259
IndexScanDesc spgbeginscan(Relation rel, int keysz, int orderbysz)
Definition: spgscan.c:295
amcanreturn_function amcanreturn
Definition: amapi.h:263
aminitparallelscan_function aminitparallelscan
Definition: amapi.h:280
amrestrpos_function amrestrpos
Definition: amapi.h:276

◆ SpGistGetBuffer()

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

Definition at line 401 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().

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

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

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

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

◆ SpGistInitBuffer()

void SpGistInitBuffer ( Buffer  b,
uint16  f 
)

Definition at line 555 of file spgutils.c.

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

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

556 {
557  Assert(BufferGetPageSize(b) == BLCKSZ);
559 }
#define BufferGetPage(buffer)
Definition: bufmgr.h:169
#define BufferGetPageSize(buffer)
Definition: bufmgr.h:156
#define Assert(condition)
Definition: c.h:800
void SpGistInitPage(Page page, uint16 f)
Definition: spgutils.c:540

◆ SpGistInitMetapage()

void SpGistInitMetapage ( Page  page)

Definition at line 565 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().

566 {
567  SpGistMetaPageData *metadata;
568  int i;
569 
571  metadata = SpGistPageGetMeta(page);
572  memset(metadata, 0, sizeof(SpGistMetaPageData));
573  metadata->magicNumber = SPGIST_MAGIC_NUMBER;
574 
575  /* initialize last-used-page cache to empty */
576  for (i = 0; i < SPGIST_CACHED_PAGES; i++)
578 
579  /*
580  * Set pd_lower just past the end of the metadata. This is essential,
581  * because without doing so, metadata will be lost if xlog.c compresses
582  * the page.
583  */
584  ((PageHeader) page)->pd_lower =
585  ((char *) metadata + sizeof(SpGistMetaPageData)) - (char *) page;
586 }
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:540
int i

◆ SpGistInitPage()

void SpGistInitPage ( Page  page,
uint16  f 
)

Definition at line 540 of file spgutils.c.

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

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

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

◆ SpGistNewBuffer()

Buffer SpGistNewBuffer ( Relation  index)

Definition at line 217 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().

218 {
219  Buffer buffer;
220  bool needLock;
221 
222  /* First, try to get a page from FSM */
223  for (;;)
224  {
225  BlockNumber blkno = GetFreeIndexPage(index);
226 
227  if (blkno == InvalidBlockNumber)
228  break; /* nothing known to FSM */
229 
230  /*
231  * The fixed pages shouldn't ever be listed in FSM, but just in case
232  * one is, ignore it.
233  */
234  if (SpGistBlockIsFixed(blkno))
235  continue;
236 
237  buffer = ReadBuffer(index, blkno);
238 
239  /*
240  * We have to guard against the possibility that someone else already
241  * recycled this page; the buffer may be locked if so.
242  */
243  if (ConditionalLockBuffer(buffer))
244  {
245  Page page = BufferGetPage(buffer);
246 
247  if (PageIsNew(page))
248  return buffer; /* OK to use, if never initialized */
249 
250  if (SpGistPageIsDeleted(page) || PageIsEmpty(page))
251  return buffer; /* OK to use */
252 
254  }
255 
256  /* Can't use it, so release buffer and try again */
257  ReleaseBuffer(buffer);
258  }
259 
260  /* Must extend the file */
261  needLock = !RELATION_IS_LOCAL(index);
262  if (needLock)
264 
265  buffer = ReadBuffer(index, P_NEW);
267 
268  if (needLock)
270 
271  return buffer;
272 }
#define BUFFER_LOCK_UNLOCK
Definition: bufmgr.h:96
#define PageIsEmpty(page)
Definition: bufpage.h:222
#define ExclusiveLock
Definition: lockdefs.h:44
#define RELATION_IS_LOCAL(relation)
Definition: rel.h:584
uint32 BlockNumber
Definition: block.h:31
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3513
#define P_NEW
Definition: bufmgr.h:91
#define BUFFER_LOCK_EXCLUSIVE
Definition: bufmgr.h:98
#define SpGistBlockIsFixed(blkno)
#define BufferGetPage(buffer)
Definition: bufmgr.h:169
bool ConditionalLockBuffer(Buffer buffer)
Definition: bufmgr.c:3778
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:3752
BlockNumber GetFreeIndexPage(Relation rel)
Definition: indexfsm.c:38
#define SpGistPageIsDeleted(page)
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:607
#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 884 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().

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

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

◆ SpGistUpdateMetaPage()

void SpGistUpdateMetaPage ( Relation  index)

Definition at line 282 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().

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

◆ spgoptions()

bytea* spgoptions ( Datum  reloptions,
bool  validate 
)

Definition at line 592 of file spgutils.c.

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

Referenced by spghandler().

593 {
594  static const relopt_parse_elt tab[] = {
596  };
597 
598  return (bytea *) build_reloptions(reloptions, validate,
600  sizeof(SpGistOptions),
601  tab, lengthof(tab));
602 
603 }
#define lengthof(array)
Definition: c.h:730
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:1887
int fillfactor
Definition: pgbench.c:160
Definition: c.h:617
#define offsetof(type, field)
Definition: c.h:723

◆ spgproperty()

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

Definition at line 979 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().

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