PostgreSQL Source Code  git master
spgutils.c File Reference
#include "postgres.h"
#include "access/reloptions.h"
#include "access/spgist_private.h"
#include "access/transam.h"
#include "access/xact.h"
#include "storage/bufmgr.h"
#include "storage/indexfsm.h"
#include "storage/lmgr.h"
#include "utils/builtins.h"
#include "utils/index_selfuncs.h"
#include "utils/lsyscache.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)
 

Macro Definition Documentation

◆ GET_LUP

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

Definition at line 309 of file spgutils.c.

Referenced by SpGistGetBuffer(), and SpGistSetLastUsedPage().

Function Documentation

◆ allocNewBuffer()

static Buffer allocNewBuffer ( Relation  index,
int  flags 
)
static

Definition at line 332 of file spgutils.c.

References SpGistLastUsedPage::blkno, buffer, 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().

333 {
334  SpGistCache *cache = spgGetCache(index);
335  uint16 pageflags = 0;
336 
337  if (GBUF_REQ_LEAF(flags))
338  pageflags |= SPGIST_LEAF;
339  if (GBUF_REQ_NULLS(flags))
340  pageflags |= SPGIST_NULLS;
341 
342  for (;;)
343  {
344  Buffer buffer;
345 
346  buffer = SpGistNewBuffer(index);
347  SpGistInitBuffer(buffer, pageflags);
348 
349  if (pageflags & SPGIST_LEAF)
350  {
351  /* Leaf pages have no parity concerns, so just use it */
352  return buffer;
353  }
354  else
355  {
356  BlockNumber blkno = BufferGetBlockNumber(buffer);
357  int blkFlags = GBUF_INNER_PARITY(blkno);
358 
359  if ((flags & GBUF_PARITY_MASK) == blkFlags)
360  {
361  /* Page has right parity, use it */
362  return buffer;
363  }
364  else
365  {
366  /* Page has wrong parity, record it in cache and try again */
367  if (pageflags & SPGIST_NULLS)
368  blkFlags |= GBUF_NULLS;
369  cache->lastUsedPages.cachedPage[blkFlags].blkno = blkno;
370  cache->lastUsedPages.cachedPage[blkFlags].freeSpace =
372  UnlockReleaseBuffer(buffer);
373  }
374  }
375  }
376 }
SpGistCache * spgGetCache(Relation index)
Definition: spgutils.c:92
#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:313
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3332
#define GBUF_INNER_PARITY(x)
void SpGistInitBuffer(Buffer b, uint16 f)
Definition: spgutils.c:543
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
Buffer SpGistNewBuffer(Relation index)
Definition: spgutils.c:204
#define GBUF_PARITY_MASK
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:215
#define GBUF_NULLS
Size PageGetExactFreeSpace(Page page)
Definition: bufpage.c:629
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2605
#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 81 of file spgutils.c.

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

Referenced by spgGetCache().

82 {
83  desc->type = type;
84  get_typlenbyval(type, &desc->attlen, &desc->attbyval);
85 }
void get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval)
Definition: lsyscache.c:2005

◆ initSpGistState()

void initSpGistState ( SpGistState state,
Relation  index 
)

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

175 {
176  SpGistCache *cache;
177 
178  /* Get cached static information about index */
179  cache = spgGetCache(index);
180 
181  state->config = cache->config;
182  state->attType = cache->attType;
183  state->attLeafType = cache->attLeafType;
184  state->attPrefixType = cache->attPrefixType;
185  state->attLabelType = cache->attLabelType;
186 
187  /* Make workspace for constructing dead tuples */
189 
190  /* Set XID to use in redirection tuples */
191  state->myXid = GetTopTransactionIdIfAny();
192 
193  /* Assume we're not in an index build (spgbuild will override) */
194  state->isBuild = false;
195 }
SpGistTypeDesc attLeafType
SpGistTypeDesc attPrefixType
SpGistCache * spgGetCache(Relation index)
Definition: spgutils.c:92
#define SGDTSIZE
SpGistTypeDesc attLeafType
SpGistTypeDesc attType
SpGistTypeDesc attLabelType
SpGistTypeDesc attType
spgConfigOut config
TransactionId myXid
TransactionId GetTopTransactionIdIfAny(void)
Definition: xact.c:405
spgConfigOut config
void * palloc0(Size size)
Definition: mcxt.c:864
char * deadTupleStorage
SpGistTypeDesc attLabelType
SpGistTypeDesc attPrefixType

◆ memcpyDatum()

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

Definition at line 610 of file spgutils.c.

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

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

611 {
612  unsigned int size;
613 
614  if (att->attbyval)
615  {
616  memcpy(target, &datum, sizeof(Datum));
617  }
618  else
619  {
620  size = (att->attlen > 0) ? att->attlen : VARSIZE_ANY(datum);
621  memcpy(target, DatumGetPointer(datum), size);
622  }
623 }
uintptr_t Datum
Definition: postgres.h:365
#define VARSIZE_ANY(PTR)
Definition: postgres.h:333
#define DatumGetPointer(X)
Definition: postgres.h:532

◆ spgExtractNodeLabels()

Datum* spgExtractNodeLabels ( SpGistState state,
SpGistInnerTuple  innerTuple 
)

Definition at line 821 of file spgutils.c.

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

Referenced by spgdoinsert(), and spgWalk().

822 {
823  Datum *nodeLabels;
824  int i;
825  SpGistNodeTuple node;
826 
827  /* Either all the labels must be NULL, or none. */
828  node = SGITNODEPTR(innerTuple);
829  if (IndexTupleHasNulls(node))
830  {
831  SGITITERATE(innerTuple, i, node)
832  {
833  if (!IndexTupleHasNulls(node))
834  elog(ERROR, "some but not all node labels are null in SPGiST inner tuple");
835  }
836  /* They're all null, so just return NULL */
837  return NULL;
838  }
839  else
840  {
841  nodeLabels = (Datum *) palloc(sizeof(Datum) * innerTuple->nNodes);
842  SGITITERATE(innerTuple, i, node)
843  {
844  if (IndexTupleHasNulls(node))
845  elog(ERROR, "some but not all node labels are null in SPGiST inner tuple");
846  nodeLabels[i] = SGNTDATUM(node, state);
847  }
848  return nodeLabels;
849  }
850 }
#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:365
void * palloc(Size size)
Definition: mcxt.c:835
int i
#define SGNTDATUM(x, s)
#define elog
Definition: elog.h:219

◆ spgFormDeadTuple()

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

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

793 {
795 
796  tuple->tupstate = tupstate;
797  tuple->size = SGDTSIZE;
799 
800  if (tupstate == SPGIST_REDIRECT)
801  {
802  ItemPointerSet(&tuple->pointer, blkno, offnum);
804  tuple->xid = state->myXid;
805  }
806  else
807  {
809  tuple->xid = InvalidTransactionId;
810  }
811 
812  return tuple;
813 }
#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:688
#define ItemPointerSetInvalid(pointer)
Definition: itemptr.h:150
#define TransactionIdIsValid(xid)
Definition: transam.h:41
#define ItemPointerSet(pointer, blockNumber, offNum)
Definition: itemptr.h:105

◆ spgFormInnerTuple()

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

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

710 {
711  SpGistInnerTuple tup;
712  unsigned int size;
713  unsigned int prefixSize;
714  int i;
715  char *ptr;
716 
717  /* Compute size needed */
718  if (hasPrefix)
719  prefixSize = SpGistGetTypeSize(&state->attPrefixType, prefix);
720  else
721  prefixSize = 0;
722 
723  size = SGITHDRSZ + prefixSize;
724 
725  /* Note: we rely on node tuple sizes to be maxaligned already */
726  for (i = 0; i < nNodes; i++)
727  size += IndexTupleSize(nodes[i]);
728 
729  /*
730  * Ensure that we can replace the tuple with a dead tuple later. This
731  * test is unnecessary given current tuple layouts, but let's be safe.
732  */
733  if (size < SGDTSIZE)
734  size = SGDTSIZE;
735 
736  /*
737  * Inner tuple should be small enough to fit on a page
738  */
739  if (size > SPGIST_PAGE_CAPACITY - sizeof(ItemIdData))
740  ereport(ERROR,
741  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
742  errmsg("SP-GiST inner tuple size %zu exceeds maximum %zu",
743  (Size) size,
744  SPGIST_PAGE_CAPACITY - sizeof(ItemIdData)),
745  errhint("Values larger than a buffer page cannot be indexed.")));
746 
747  /*
748  * Check for overflow of header fields --- probably can't fail if the
749  * above succeeded, but let's be paranoid
750  */
751  if (size > SGITMAXSIZE ||
752  prefixSize > SGITMAXPREFIXSIZE ||
753  nNodes > SGITMAXNNODES)
754  elog(ERROR, "SPGiST inner tuple header field is too small");
755 
756  /* OK, form the tuple */
757  tup = (SpGistInnerTuple) palloc0(size);
758 
759  tup->nNodes = nNodes;
760  tup->prefixSize = prefixSize;
761  tup->size = size;
762 
763  if (hasPrefix)
764  memcpyDatum(SGITDATAPTR(tup), &state->attPrefixType, prefix);
765 
766  ptr = (char *) SGITNODEPTR(tup);
767 
768  for (i = 0; i < nNodes; i++)
769  {
770  SpGistNodeTuple node = nodes[i];
771 
772  memcpy(ptr, node, IndexTupleSize(node));
773  ptr += IndexTupleSize(node);
774  }
775 
776  return tup;
777 }
#define SGITNODEPTR(x)
SpGistTypeDesc attPrefixType
SpGistInnerTupleData * SpGistInnerTuple
int errhint(const char *fmt,...)
Definition: elog.c:987
#define SGITMAXPREFIXSIZE
#define SGDTSIZE
int errcode(int sqlerrcode)
Definition: elog.c:575
#define ERROR
Definition: elog.h:43
unsigned int prefixSize
#define SGITMAXSIZE
#define SGITDATAPTR(x)
#define SGITMAXNNODES
#define ereport(elevel, rest)
Definition: elog.h:122
unsigned int SpGistGetTypeSize(SpGistTypeDesc *att, Datum datum)
Definition: spgutils.c:592
void * palloc0(Size size)
Definition: mcxt.c:864
#define SPGIST_PAGE_CAPACITY
size_t Size
Definition: c.h:422
static void memcpyDatum(void *target, SpGistTypeDesc *att, Datum datum)
Definition: spgutils.c:610
int errmsg(const char *fmt,...)
Definition: elog.c:797
int i
#define elog
Definition: elog.h:219
#define SGITHDRSZ
#define IndexTupleSize(itup)
Definition: itup.h:70

◆ spgFormLeafTuple()

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

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

631 {
632  SpGistLeafTuple tup;
633  unsigned int size;
634 
635  /* compute space needed (note result is already maxaligned) */
636  size = SGLTHDRSZ;
637  if (!isnull)
638  size += SpGistGetTypeSize(&state->attLeafType, datum);
639 
640  /*
641  * Ensure that we can replace the tuple with a dead tuple later. This
642  * test is unnecessary when !isnull, but let's be safe.
643  */
644  if (size < SGDTSIZE)
645  size = SGDTSIZE;
646 
647  /* OK, form the tuple */
648  tup = (SpGistLeafTuple) palloc0(size);
649 
650  tup->size = size;
652  tup->heapPtr = *heapPtr;
653  if (!isnull)
654  memcpyDatum(SGLTDATAPTR(tup), &state->attLeafType, datum);
655 
656  return tup;
657 }
#define SGDTSIZE
SpGistTypeDesc attLeafType
#define SGLTDATAPTR(x)
#define SGLTHDRSZ
unsigned int SpGistGetTypeSize(SpGistTypeDesc *att, Datum datum)
Definition: spgutils.c:592
void * palloc0(Size size)
Definition: mcxt.c:864
#define InvalidOffsetNumber
Definition: off.h:26
OffsetNumber nextOffset
static void memcpyDatum(void *target, SpGistTypeDesc *att, Datum datum)
Definition: spgutils.c:610
ItemPointerData heapPtr
SpGistLeafTupleData * SpGistLeafTuple

◆ spgFormNodeTuple()

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

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

667 {
668  SpGistNodeTuple tup;
669  unsigned int size;
670  unsigned short infomask = 0;
671 
672  /* compute space needed (note result is already maxaligned) */
673  size = SGNTHDRSZ;
674  if (!isnull)
675  size += SpGistGetTypeSize(&state->attLabelType, label);
676 
677  /*
678  * Here we make sure that the size will fit in the field reserved for it
679  * in t_info.
680  */
681  if ((size & INDEX_SIZE_MASK) != size)
682  ereport(ERROR,
683  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
684  errmsg("index row requires %zu bytes, maximum size is %zu",
685  (Size) size, (Size) INDEX_SIZE_MASK)));
686 
687  tup = (SpGistNodeTuple) palloc0(size);
688 
689  if (isnull)
690  infomask |= INDEX_NULL_MASK;
691  /* we don't bother setting the INDEX_VAR_MASK bit */
692  infomask |= size;
693  tup->t_info = infomask;
694 
695  /* The TID field will be filled in later */
697 
698  if (!isnull)
699  memcpyDatum(SGNTDATAPTR(tup), &state->attLabelType, label);
700 
701  return tup;
702 }
ItemPointerData t_tid
Definition: itup.h:37
#define INDEX_SIZE_MASK
Definition: itup.h:65
int errcode(int sqlerrcode)
Definition: elog.c:575
SpGistTypeDesc attLabelType
#define SGNTHDRSZ
#define ERROR
Definition: elog.h:43
#define INDEX_NULL_MASK
Definition: itup.h:68
#define ereport(elevel, rest)
Definition: elog.h:122
unsigned int SpGistGetTypeSize(SpGistTypeDesc *att, Datum datum)
Definition: spgutils.c:592
void * palloc0(Size size)
Definition: mcxt.c:864
static char * label
Definition: pg_basebackup.c:82
#define SGNTDATAPTR(x)
size_t Size
Definition: c.h:422
#define ItemPointerSetInvalid(pointer)
Definition: itemptr.h:150
static void memcpyDatum(void *target, SpGistTypeDesc *att, Datum datum)
Definition: spgutils.c:610
int errmsg(const char *fmt,...)
Definition: elog.c:797
unsigned short t_info
Definition: itup.h:49
SpGistNodeTupleData * SpGistNodeTuple

◆ spgGetCache()

SpGistCache* spgGetCache ( Relation  index)

Definition at line 92 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(), tupleDesc::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().

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

◆ spghandler()

Datum spghandler ( PG_FUNCTION_ARGS  )

Definition at line 35 of file spgutils.c.

References IndexAmRoutine::ambeginscan, IndexAmRoutine::ambuild, IndexAmRoutine::ambuildempty, IndexAmRoutine::ambulkdelete, IndexAmRoutine::amcanbackward, 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::ampredlocks, IndexAmRoutine::amproperty, IndexAmRoutine::amrescan, IndexAmRoutine::amrestrpos, IndexAmRoutine::amsearcharray, IndexAmRoutine::amsearchnulls, IndexAmRoutine::amstorage, IndexAmRoutine::amstrategies, IndexAmRoutine::amsupport, IndexAmRoutine::amvacuumcleanup, IndexAmRoutine::amvalidate, InvalidOid, makeNode, PG_RETURN_POINTER, spgbeginscan(), spgbuild(), spgbuildempty(), spgbulkdelete(), spgcanreturn(), spgcostestimate(), spgendscan(), spggetbitmap(), spggettuple(), spginsert(), SPGISTNProc, spgoptions(), spgrescan(), spgvacuumcleanup(), and spgvalidate().

36 {
38 
39  amroutine->amstrategies = 0;
40  amroutine->amsupport = SPGISTNProc;
41  amroutine->amcanorder = false;
42  amroutine->amcanorderbyop = false;
43  amroutine->amcanbackward = false;
44  amroutine->amcanunique = false;
45  amroutine->amcanmulticol = false;
46  amroutine->amoptionalkey = true;
47  amroutine->amsearcharray = false;
48  amroutine->amsearchnulls = true;
49  amroutine->amstorage = false;
50  amroutine->amclusterable = false;
51  amroutine->ampredlocks = false;
52  amroutine->amcanparallel = false;
53  amroutine->amkeytype = InvalidOid;
54 
55  amroutine->ambuild = spgbuild;
56  amroutine->ambuildempty = spgbuildempty;
57  amroutine->aminsert = spginsert;
58  amroutine->ambulkdelete = spgbulkdelete;
59  amroutine->amvacuumcleanup = spgvacuumcleanup;
60  amroutine->amcanreturn = spgcanreturn;
61  amroutine->amcostestimate = spgcostestimate;
62  amroutine->amoptions = spgoptions;
63  amroutine->amproperty = NULL;
64  amroutine->amvalidate = spgvalidate;
65  amroutine->ambeginscan = spgbeginscan;
66  amroutine->amrescan = spgrescan;
67  amroutine->amgettuple = spggettuple;
68  amroutine->amgetbitmap = spggetbitmap;
69  amroutine->amendscan = spgendscan;
70  amroutine->ammarkpos = NULL;
71  amroutine->amrestrpos = NULL;
72  amroutine->amestimateparallelscan = NULL;
73  amroutine->aminitparallelscan = NULL;
74  amroutine->amparallelrescan = NULL;
75 
76  PG_RETURN_POINTER(amroutine);
77 }
ambeginscan_function ambeginscan
Definition: amapi.h:208
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:321
ambulkdelete_function ambulkdelete
Definition: amapi.h:201
bool amcanmulticol
Definition: amapi.h:179
uint16 amsupport
Definition: amapi.h:169
amgettuple_function amgettuple
Definition: amapi.h:210
bool amcanorderbyop
Definition: amapi.h:173
amproperty_function amproperty
Definition: amapi.h:206
IndexBulkDeleteResult * spgvacuumcleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats)
Definition: spgvacuum.c:917
amparallelrescan_function amparallelrescan
Definition: amapi.h:219
bool amstorage
Definition: amapi.h:187
void spgrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys, ScanKey orderbys, int norderbys)
Definition: spgscan.c:207
bool ampredlocks
Definition: amapi.h:191
aminsert_function aminsert
Definition: amapi.h:200
bool spginsert(Relation index, Datum *values, bool *isnull, ItemPointer ht_ctid, Relation heapRel, IndexUniqueCheck checkUnique, IndexInfo *indexInfo)
Definition: spginsert.c:209
Oid amkeytype
Definition: amapi.h:195
void spgendscan(IndexScanDesc scan)
Definition: spgscan.c:227
bool amoptionalkey
Definition: amapi.h:181
amvalidate_function amvalidate
Definition: amapi.h:207
bool spgcanreturn(Relation index, int attno)
Definition: spgscan.c:648
amgetbitmap_function amgetbitmap
Definition: amapi.h:211
IndexBulkDeleteResult * spgbulkdelete(IndexVacuumInfo *info, IndexBulkDeleteResult *stats, IndexBulkDeleteCallback callback, void *callback_state)
Definition: spgvacuum.c:886
ambuild_function ambuild
Definition: amapi.h:198
amoptions_function amoptions
Definition: amapi.h:205
amcostestimate_function amcostestimate
Definition: amapi.h:204
bool amcanunique
Definition: amapi.h:177
amvacuumcleanup_function amvacuumcleanup
Definition: amapi.h:202
amendscan_function amendscan
Definition: amapi.h:212
bool amcanbackward
Definition: amapi.h:175
int64 spggetbitmap(IndexScanDesc scan, TIDBitmap *tbm)
Definition: spgscan.c:568
void spgbuildempty(Relation index)
Definition: spginsert.c:158
amrescan_function amrescan
Definition: amapi.h:209
bool amcanparallel
Definition: amapi.h:193
bytea * spgoptions(Datum reloptions, bool validate)
Definition: spgutils.c:580
bool amsearchnulls
Definition: amapi.h:185
bool amclusterable
Definition: amapi.h:189
bool amsearcharray
Definition: amapi.h:183
#define InvalidOid
Definition: postgres_ext.h:36
void spgcostestimate(PlannerInfo *root, IndexPath *path, double loop_count, Cost *indexStartupCost, Cost *indexTotalCost, Selectivity *indexSelectivity, double *indexCorrelation, double *indexPages)
Definition: selfuncs.c:7282
#define makeNode(_type_)
Definition: nodes.h:561
ammarkpos_function ammarkpos
Definition: amapi.h:213
bool amcanorder
Definition: amapi.h:171
amestimateparallelscan_function amestimateparallelscan
Definition: amapi.h:217
IndexBuildResult * spgbuild(Relation heap, Relation index, IndexInfo *indexInfo)
Definition: spginsert.c:70
uint16 amstrategies
Definition: amapi.h:167
#define SPGISTNProc
Definition: spgist.h:35
bool spgvalidate(Oid opclassoid)
Definition: spgvalidate.c:39
bool spggettuple(IndexScanDesc scan, ScanDirection dir)
Definition: spgscan.c:605
ambuildempty_function ambuildempty
Definition: amapi.h:199
IndexScanDesc spgbeginscan(Relation rel, int keysz, int orderbysz)
Definition: spgscan.c:181
amcanreturn_function amcanreturn
Definition: amapi.h:203
aminitparallelscan_function aminitparallelscan
Definition: amapi.h:218
amrestrpos_function amrestrpos
Definition: amapi.h:214

◆ SpGistGetBuffer()

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

Definition at line 388 of file spgutils.c.

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

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

389 {
390  SpGistCache *cache = spgGetCache(index);
391  SpGistLastUsedPage *lup;
392 
393  /* Bail out if even an empty page wouldn't meet the demand */
394  if (needSpace > SPGIST_PAGE_CAPACITY)
395  elog(ERROR, "desired SPGiST tuple size is too big");
396 
397  /*
398  * If possible, increase the space request to include relation's
399  * fillfactor. This ensures that when we add unrelated tuples to a page,
400  * we try to keep 100-fillfactor% available for adding tuples that are
401  * related to the ones already on it. But fillfactor mustn't cause an
402  * error for requests that would otherwise be legal.
403  */
404  needSpace += RelationGetTargetPageFreeSpace(index,
406  needSpace = Min(needSpace, SPGIST_PAGE_CAPACITY);
407 
408  /* Get the cache entry for this flags setting */
409  lup = GET_LUP(cache, flags);
410 
411  /* If we have nothing cached, just turn it over to allocNewBuffer */
412  if (lup->blkno == InvalidBlockNumber)
413  {
414  *isNew = true;
415  return allocNewBuffer(index, flags);
416  }
417 
418  /* fixed pages should never be in cache */
420 
421  /* If cached freeSpace isn't enough, don't bother looking at the page */
422  if (lup->freeSpace >= needSpace)
423  {
424  Buffer buffer;
425  Page page;
426 
427  buffer = ReadBuffer(index, lup->blkno);
428 
429  if (!ConditionalLockBuffer(buffer))
430  {
431  /*
432  * buffer is locked by another process, so return a new buffer
433  */
434  ReleaseBuffer(buffer);
435  *isNew = true;
436  return allocNewBuffer(index, flags);
437  }
438 
439  page = BufferGetPage(buffer);
440 
441  if (PageIsNew(page) || SpGistPageIsDeleted(page) || PageIsEmpty(page))
442  {
443  /* OK to initialize the page */
444  uint16 pageflags = 0;
445 
446  if (GBUF_REQ_LEAF(flags))
447  pageflags |= SPGIST_LEAF;
448  if (GBUF_REQ_NULLS(flags))
449  pageflags |= SPGIST_NULLS;
450  SpGistInitBuffer(buffer, pageflags);
451  lup->freeSpace = PageGetExactFreeSpace(page) - needSpace;
452  *isNew = true;
453  return buffer;
454  }
455 
456  /*
457  * Check that page is of right type and has enough space. We must
458  * recheck this since our cache isn't necessarily up to date.
459  */
460  if ((GBUF_REQ_LEAF(flags) ? SpGistPageIsLeaf(page) : !SpGistPageIsLeaf(page)) &&
462  {
463  int freeSpace = PageGetExactFreeSpace(page);
464 
465  if (freeSpace >= needSpace)
466  {
467  /* Success, update freespace info and return the buffer */
468  lup->freeSpace = freeSpace - needSpace;
469  *isNew = false;
470  return buffer;
471  }
472  }
473 
474  /*
475  * fallback to allocation of new buffer
476  */
477  UnlockReleaseBuffer(buffer);
478  }
479 
480  /* No success with cache, so return a new buffer */
481  *isNew = true;
482  return allocNewBuffer(index, flags);
483 }
#define PageIsEmpty(page)
Definition: bufpage.h:218
#define SpGistPageIsLeaf(page)
SpGistCache * spgGetCache(Relation index)
Definition: spgutils.c:92
#define GET_LUP(c, f)
Definition: spgutils.c:309
#define Min(x, y)
Definition: c.h:846
#define SPGIST_NULLS
static Buffer allocNewBuffer(Relation index, int flags)
Definition: spgutils.c:332
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3309
#define SPGIST_DEFAULT_FILLFACTOR
Definition: spgist.h:25
#define GBUF_REQ_NULLS(flags)
unsigned short uint16
Definition: c.h:313
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3332
#define ERROR
Definition: elog.h:43
#define SpGistBlockIsFixed(blkno)
void SpGistInitBuffer(Buffer b, uint16 f)
Definition: spgutils.c:543
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
bool ConditionalLockBuffer(Buffer buffer)
Definition: bufmgr.c:3572
#define RelationGetTargetPageFreeSpace(relation, defaultff)
Definition: rel.h:316
#define SPGIST_PAGE_CAPACITY
#define SpGistPageStoresNulls(page)
#define Assert(condition)
Definition: c.h:688
#define SpGistPageIsDeleted(page)
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:215
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:594
#define InvalidBlockNumber
Definition: block.h:33
Size PageGetExactFreeSpace(Page page)
Definition: bufpage.c:629
#define PageIsNew(page)
Definition: bufpage.h:225
#define elog
Definition: elog.h:219
#define SPGIST_LEAF
int Buffer
Definition: buf.h:23
Pointer Page
Definition: bufpage.h:74
#define GBUF_REQ_LEAF(flags)

◆ SpGistGetTypeSize()

unsigned int SpGistGetTypeSize ( SpGistTypeDesc att,
Datum  datum 
)

Definition at line 592 of file spgutils.c.

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

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

593 {
594  unsigned int size;
595 
596  if (att->attbyval)
597  size = sizeof(Datum);
598  else if (att->attlen > 0)
599  size = att->attlen;
600  else
601  size = VARSIZE_ANY(datum);
602 
603  return MAXALIGN(size);
604 }
uintptr_t Datum
Definition: postgres.h:365
#define VARSIZE_ANY(PTR)
Definition: postgres.h:333
#define MAXALIGN(LEN)
Definition: c.h:641

◆ SpGistInitBuffer()

void SpGistInitBuffer ( Buffer  b,
uint16  f 
)

Definition at line 543 of file spgutils.c.

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

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

544 {
545  Assert(BufferGetPageSize(b) == BLCKSZ);
547 }
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
#define BufferGetPageSize(buffer)
Definition: bufmgr.h:147
#define Assert(condition)
Definition: c.h:688
void SpGistInitPage(Page page, uint16 f)
Definition: spgutils.c:528

◆ SpGistInitMetapage()

void SpGistInitMetapage ( Page  page)

Definition at line 553 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(), spgbuildempty(), and spgRedoCreateIndex().

554 {
555  SpGistMetaPageData *metadata;
556  int i;
557 
559  metadata = SpGistPageGetMeta(page);
560  memset(metadata, 0, sizeof(SpGistMetaPageData));
561  metadata->magicNumber = SPGIST_MAGIC_NUMBER;
562 
563  /* initialize last-used-page cache to empty */
564  for (i = 0; i < SPGIST_CACHED_PAGES; i++)
566 
567  /*
568  * Set pd_lower just past the end of the metadata. This is essential,
569  * because without doing so, metadata will be lost if xlog.c compresses
570  * the page.
571  */
572  ((PageHeader) page)->pd_lower =
573  ((char *) metadata + sizeof(SpGistMetaPageData)) - (char *) page;
574 }
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:528
int i

◆ SpGistInitPage()

void SpGistInitPage ( Page  page,
uint16  f 
)

Definition at line 528 of file spgutils.c.

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

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

529 {
530  SpGistPageOpaque opaque;
531 
532  PageInit(page, BLCKSZ, MAXALIGN(sizeof(SpGistPageOpaqueData)));
533  opaque = SpGistPageGetOpaque(page);
534  memset(opaque, 0, sizeof(SpGistPageOpaqueData));
535  opaque->flags = f;
536  opaque->spgist_page_id = SPGIST_PAGE_ID;
537 }
#define SPGIST_PAGE_ID
#define MAXALIGN(LEN)
Definition: c.h:641
#define SpGistPageGetOpaque(page)
void PageInit(Page page, Size pageSize, Size specialSize)
Definition: bufpage.c:41

◆ SpGistNewBuffer()

Buffer SpGistNewBuffer ( Relation  index)

Definition at line 204 of file spgutils.c.

References buffer, 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().

205 {
206  Buffer buffer;
207  bool needLock;
208 
209  /* First, try to get a page from FSM */
210  for (;;)
211  {
212  BlockNumber blkno = GetFreeIndexPage(index);
213 
214  if (blkno == InvalidBlockNumber)
215  break; /* nothing known to FSM */
216 
217  /*
218  * The fixed pages shouldn't ever be listed in FSM, but just in case
219  * one is, ignore it.
220  */
221  if (SpGistBlockIsFixed(blkno))
222  continue;
223 
224  buffer = ReadBuffer(index, blkno);
225 
226  /*
227  * We have to guard against the possibility that someone else already
228  * recycled this page; the buffer may be locked if so.
229  */
230  if (ConditionalLockBuffer(buffer))
231  {
232  Page page = BufferGetPage(buffer);
233 
234  if (PageIsNew(page))
235  return buffer; /* OK to use, if never initialized */
236 
237  if (SpGistPageIsDeleted(page) || PageIsEmpty(page))
238  return buffer; /* OK to use */
239 
241  }
242 
243  /* Can't use it, so release buffer and try again */
244  ReleaseBuffer(buffer);
245  }
246 
247  /* Must extend the file */
248  needLock = !RELATION_IS_LOCAL(index);
249  if (needLock)
251 
252  buffer = ReadBuffer(index, P_NEW);
254 
255  if (needLock)
257 
258  return buffer;
259 }
#define BUFFER_LOCK_UNLOCK
Definition: bufmgr.h:87
#define PageIsEmpty(page)
Definition: bufpage.h:218
#define ExclusiveLock
Definition: lockdefs.h:44
#define RELATION_IS_LOCAL(relation)
Definition: rel.h:532
uint32 BlockNumber
Definition: block.h:31
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3309
#define P_NEW
Definition: bufmgr.h:82
#define BUFFER_LOCK_EXCLUSIVE
Definition: bufmgr.h:89
#define SpGistBlockIsFixed(blkno)
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
bool ConditionalLockBuffer(Buffer buffer)
Definition: bufmgr.c:3572
void LockRelationForExtension(Relation relation, LOCKMODE lockmode)
Definition: lmgr.c:332
void UnlockRelationForExtension(Relation relation, LOCKMODE lockmode)
Definition: lmgr.c:382
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3546
BlockNumber GetFreeIndexPage(Relation rel)
Definition: indexfsm.c:38
#define SpGistPageIsDeleted(page)
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:215
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:594
#define InvalidBlockNumber
Definition: block.h:33
#define PageIsNew(page)
Definition: bufpage.h:225
int Buffer
Definition: buf.h:23
Pointer Page
Definition: bufpage.h:74

◆ SpGistPageAddNewItem()

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

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

866 {
867  SpGistPageOpaque opaque = SpGistPageGetOpaque(page);
868  OffsetNumber i,
869  maxoff,
870  offnum;
871 
872  if (opaque->nPlaceholder > 0 &&
873  PageGetExactFreeSpace(page) + SGDTSIZE >= MAXALIGN(size))
874  {
875  /* Try to replace a placeholder */
876  maxoff = PageGetMaxOffsetNumber(page);
877  offnum = InvalidOffsetNumber;
878 
879  for (;;)
880  {
881  if (startOffset && *startOffset != InvalidOffsetNumber)
882  i = *startOffset;
883  else
884  i = FirstOffsetNumber;
885  for (; i <= maxoff; i++)
886  {
888  PageGetItemId(page, i));
889 
890  if (it->tupstate == SPGIST_PLACEHOLDER)
891  {
892  offnum = i;
893  break;
894  }
895  }
896 
897  /* Done if we found a placeholder */
898  if (offnum != InvalidOffsetNumber)
899  break;
900 
901  if (startOffset && *startOffset != InvalidOffsetNumber)
902  {
903  /* Hint was no good, re-search from beginning */
904  *startOffset = InvalidOffsetNumber;
905  continue;
906  }
907 
908  /* Hmm, no placeholder found? */
909  opaque->nPlaceholder = 0;
910  break;
911  }
912 
913  if (offnum != InvalidOffsetNumber)
914  {
915  /* Replace the placeholder tuple */
916  PageIndexTupleDelete(page, offnum);
917 
918  offnum = PageAddItem(page, item, size, offnum, false, false);
919 
920  /*
921  * We should not have failed given the size check at the top of
922  * the function, but test anyway. If we did fail, we must PANIC
923  * because we've already deleted the placeholder tuple, and
924  * there's no other way to keep the damage from getting to disk.
925  */
926  if (offnum != InvalidOffsetNumber)
927  {
928  Assert(opaque->nPlaceholder > 0);
929  opaque->nPlaceholder--;
930  if (startOffset)
931  *startOffset = offnum + 1;
932  }
933  else
934  elog(PANIC, "failed to add item of size %u to SPGiST index page",
935  (int) size);
936 
937  return offnum;
938  }
939  }
940 
941  /* No luck in replacing a placeholder, so just add it to the page */
942  offnum = PageAddItem(page, item, size,
943  InvalidOffsetNumber, false, false);
944 
945  if (offnum == InvalidOffsetNumber && !errorOK)
946  elog(ERROR, "failed to add item of size %u to SPGiST index page",
947  (int) size);
948 
949  return offnum;
950 }
#define SGDTSIZE
void PageIndexTupleDelete(Page page, OffsetNumber offnum)
Definition: bufpage.c:723
#define SPGIST_PLACEHOLDER
#define PageAddItem(page, item, size, offsetNumber, overwrite, is_heap)
Definition: bufpage.h:412
#define PANIC
Definition: elog.h:53
#define PageGetMaxOffsetNumber(page)
Definition: bufpage.h:353
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:231
unsigned int tupstate
#define InvalidOffsetNumber
Definition: off.h:26
#define Assert(condition)
Definition: c.h:688
#define MAXALIGN(LEN)
Definition: c.h:641
Size PageGetExactFreeSpace(Page page)
Definition: bufpage.c:629
#define SpGistPageGetOpaque(page)
int i
#define elog
Definition: elog.h:219
#define PageGetItem(page, itemId)
Definition: bufpage.h:336

◆ SpGistSetLastUsedPage()

void SpGistSetLastUsedPage ( Relation  index,
Buffer  buffer 
)

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

494 {
495  SpGistCache *cache = spgGetCache(index);
496  SpGistLastUsedPage *lup;
497  int freeSpace;
498  Page page = BufferGetPage(buffer);
500  int flags;
501 
502  /* Never enter fixed pages (root pages) in cache, though */
503  if (SpGistBlockIsFixed(blkno))
504  return;
505 
506  if (SpGistPageIsLeaf(page))
507  flags = GBUF_LEAF;
508  else
509  flags = GBUF_INNER_PARITY(blkno);
510  if (SpGistPageStoresNulls(page))
511  flags |= GBUF_NULLS;
512 
513  lup = GET_LUP(cache, flags);
514 
515  freeSpace = PageGetExactFreeSpace(page);
516  if (lup->blkno == InvalidBlockNumber || lup->blkno == blkno ||
517  lup->freeSpace < freeSpace)
518  {
519  lup->blkno = blkno;
520  lup->freeSpace = freeSpace;
521  }
522 }
#define SpGistPageIsLeaf(page)
SpGistCache * spgGetCache(Relation index)
Definition: spgutils.c:92
#define GET_LUP(c, f)
Definition: spgutils.c:309
uint32 BlockNumber
Definition: block.h:31
#define GBUF_INNER_PARITY(x)
#define SpGistBlockIsFixed(blkno)
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
#define GBUF_LEAF
#define SpGistPageStoresNulls(page)
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:215
#define InvalidBlockNumber
Definition: block.h:33
#define GBUF_NULLS
Size PageGetExactFreeSpace(Page page)
Definition: bufpage.c:629
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2605
Pointer Page
Definition: bufpage.h:74

◆ SpGistUpdateMetaPage()

void SpGistUpdateMetaPage ( Relation  index)

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

270 {
271  SpGistCache *cache = (SpGistCache *) index->rd_amcache;
272 
273  if (cache != NULL)
274  {
275  Buffer metabuffer;
276 
277  metabuffer = ReadBuffer(index, SPGIST_METAPAGE_BLKNO);
278 
279  if (ConditionalLockBuffer(metabuffer))
280  {
281  Page metapage = BufferGetPage(metabuffer);
282  SpGistMetaPageData *metadata = SpGistPageGetMeta(metapage);
283 
284  metadata->lastUsedPages = cache->lastUsedPages;
285 
286  /*
287  * Set pd_lower just past the end of the metadata. This is
288  * essential, because without doing so, metadata will be lost if
289  * xlog.c compresses the page. (We must do this here because
290  * pre-v11 versions of PG did not set the metapage's pd_lower
291  * correctly, so a pg_upgraded index might contain the wrong
292  * value.)
293  */
294  ((PageHeader) metapage)->pd_lower =
295  ((char *) metadata + sizeof(SpGistMetaPageData)) - (char *) metapage;
296 
297  MarkBufferDirty(metabuffer);
298  UnlockReleaseBuffer(metabuffer);
299  }
300  else
301  {
302  ReleaseBuffer(metabuffer);
303  }
304  }
305 }
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1450
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3309
SpGistLUPCache lastUsedPages
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3332
#define SPGIST_METAPAGE_BLKNO
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
bool ConditionalLockBuffer(Buffer buffer)
Definition: bufmgr.c:3572
SpGistLUPCache lastUsedPages
PageHeaderData * PageHeader
Definition: bufpage.h:162
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:594
#define SpGistPageGetMeta(p)
void * rd_amcache
Definition: rel.h:192
int Buffer
Definition: buf.h:23
Pointer Page
Definition: bufpage.h:74

◆ spgoptions()

bytea* spgoptions ( Datum  reloptions,
bool  validate 
)

Definition at line 580 of file spgutils.c.

References default_reloptions(), and RELOPT_KIND_SPGIST.

Referenced by spghandler().

581 {
582  return default_reloptions(reloptions, validate, RELOPT_KIND_SPGIST);
583 }
bytea * default_reloptions(Datum reloptions, bool validate, relopt_kind kind)
Definition: reloptions.c:1325