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

Referenced by SpGistGetBuffer(), and SpGistSetLastUsedPage().

Function Documentation

◆ allocNewBuffer()

static Buffer allocNewBuffer ( Relation  index,
int  flags 
)
static

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

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

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

Referenced by spgGetCache().

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

◆ initSpGistState()

void initSpGistState ( SpGistState state,
Relation  index 
)

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

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

◆ memcpyDatum()

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

Definition at line 611 of file spgutils.c.

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

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

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

◆ spgExtractNodeLabels()

Datum* spgExtractNodeLabels ( SpGistState state,
SpGistInnerTuple  innerTuple 
)

Definition at line 822 of file spgutils.c.

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

Referenced by spgdoinsert(), and spgWalk().

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

794 {
796 
797  tuple->tupstate = tupstate;
798  tuple->size = SGDTSIZE;
800 
801  if (tupstate == SPGIST_REDIRECT)
802  {
803  ItemPointerSet(&tuple->pointer, blkno, offnum);
805  tuple->xid = state->myXid;
806  }
807  else
808  {
810  tuple->xid = InvalidTransactionId;
811  }
812 
813  return tuple;
814 }
#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:699
#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 709 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().

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

◆ spgFormLeafTuple()

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

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

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

◆ spgFormNodeTuple()

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

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

668 {
669  SpGistNodeTuple tup;
670  unsigned int size;
671  unsigned short infomask = 0;
672 
673  /* compute space needed (note result is already maxaligned) */
674  size = SGNTHDRSZ;
675  if (!isnull)
676  size += SpGistGetTypeSize(&state->attLabelType, label);
677 
678  /*
679  * Here we make sure that the size will fit in the field reserved for it
680  * in t_info.
681  */
682  if ((size & INDEX_SIZE_MASK) != size)
683  ereport(ERROR,
684  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
685  errmsg("index row requires %zu bytes, maximum size is %zu",
686  (Size) size, (Size) INDEX_SIZE_MASK)));
687 
688  tup = (SpGistNodeTuple) palloc0(size);
689 
690  if (isnull)
691  infomask |= INDEX_NULL_MASK;
692  /* we don't bother setting the INDEX_VAR_MASK bit */
693  infomask |= size;
694  tup->t_info = infomask;
695 
696  /* The TID field will be filled in later */
698 
699  if (!isnull)
700  memcpyDatum(SGNTDATAPTR(tup), &state->attLabelType, label);
701 
702  return tup;
703 }
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:69
#define ereport(elevel, rest)
Definition: elog.h:122
unsigned int SpGistGetTypeSize(SpGistTypeDesc *att, Datum datum)
Definition: spgutils.c:593
void * palloc0(Size size)
Definition: mcxt.c:955
static char * label
Definition: pg_basebackup.c:84
#define SGNTDATAPTR(x)
size_t Size
Definition: c.h:433
#define ItemPointerSetInvalid(pointer)
Definition: itemptr.h:172
static void memcpyDatum(void *target, SpGistTypeDesc *att, Datum datum)
Definition: spgutils.c:611
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 93 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().

94 {
95  SpGistCache *cache;
96 
97  if (index->rd_amcache == NULL)
98  {
99  Oid atttype;
100  spgConfigIn in;
101  FmgrInfo *procinfo;
102  Buffer metabuffer;
103  SpGistMetaPageData *metadata;
104 
105  cache = MemoryContextAllocZero(index->rd_indexcxt,
106  sizeof(SpGistCache));
107 
108  /* SPGiST doesn't support multi-column indexes */
109  Assert(index->rd_att->natts == 1);
110 
111  /*
112  * Get the actual data type of the indexed column from the index
113  * tupdesc. We pass this to the opclass config function so that
114  * polymorphic opclasses are possible.
115  */
116  atttype = TupleDescAttr(index->rd_att, 0)->atttypid;
117 
118  /* Call the config function to get config info for the opclass */
119  in.attType = atttype;
120 
121  procinfo = index_getprocinfo(index, 1, SPGIST_CONFIG_PROC);
122  FunctionCall2Coll(procinfo,
123  index->rd_indcollation[0],
124  PointerGetDatum(&in),
125  PointerGetDatum(&cache->config));
126 
127  /* Get the information we need about each relevant datatype */
128  fillTypeDesc(&cache->attType, atttype);
129 
130  if (OidIsValid(cache->config.leafType) &&
131  cache->config.leafType != atttype)
132  {
134  ereport(ERROR,
135  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
136  errmsg("compress method must not defined when leaf type is different from input type")));
137 
138  fillTypeDesc(&cache->attLeafType, cache->config.leafType);
139  }
140  else
141  {
142  cache->attLeafType = cache->attType;
143  }
144 
145  fillTypeDesc(&cache->attPrefixType, cache->config.prefixType);
146  fillTypeDesc(&cache->attLabelType, cache->config.labelType);
147 
148  /* Last, get the lastUsedPages data from the metapage */
149  metabuffer = ReadBuffer(index, SPGIST_METAPAGE_BLKNO);
150  LockBuffer(metabuffer, BUFFER_LOCK_SHARE);
151 
152  metadata = SpGistPageGetMeta(BufferGetPage(metabuffer));
153 
154  if (metadata->magicNumber != SPGIST_MAGIC_NUMBER)
155  elog(ERROR, "index \"%s\" is not an SP-GiST index",
156  RelationGetRelationName(index));
157 
158  cache->lastUsedPages = metadata->lastUsedPages;
159 
160  UnlockReleaseBuffer(metabuffer);
161 
162  index->rd_amcache = (void *) cache;
163  }
164  else
165  {
166  /* assume it's up to date */
167  cache = (SpGistCache *) index->rd_amcache;
168  }
169 
170  return cache;
171 }
SpGistTypeDesc attLeafType
Definition: fmgr.h:56
FmgrInfo * index_getprocinfo(Relation irel, AttrNumber attnum, uint16 procnum)
Definition: indexam.c:855
#define PointerGetDatum(X)
Definition: postgres.h:541
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:93
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:1133
unsigned int Oid
Definition: postgres_ext.h:31
SpGistTypeDesc attType
#define OidIsValid(objectId)
Definition: c.h:605
int natts
Definition: tupdesc.h:82
SpGistLUPCache lastUsedPages
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3332
Oid * rd_indcollation
Definition: rel.h:165
#define ERROR
Definition: elog.h:43
#define SPGIST_METAPAGE_BLKNO
#define RelationGetRelationName(relation)
Definition: rel.h:441
#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:85
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:814
#define Assert(condition)
Definition: c.h:699
#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:151
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:82
#define elog
Definition: elog.h:219
void * rd_amcache
Definition: rel.h:164
int Buffer
Definition: buf.h:23
RegProcedure index_getprocid(Relation irel, AttrNumber attnum, uint16 procnum)
Definition: indexam.c:821

◆ 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::amcaninclude, IndexAmRoutine::amcanmulticol, IndexAmRoutine::amcanorder, IndexAmRoutine::amcanorderbyop, IndexAmRoutine::amcanparallel, IndexAmRoutine::amcanreturn, IndexAmRoutine::amcanunique, IndexAmRoutine::amclusterable, IndexAmRoutine::amcostestimate, IndexAmRoutine::amendscan, IndexAmRoutine::amestimateparallelscan, IndexAmRoutine::amgetbitmap, IndexAmRoutine::amgettuple, IndexAmRoutine::aminitparallelscan, IndexAmRoutine::aminsert, IndexAmRoutine::amkeytype, IndexAmRoutine::ammarkpos, IndexAmRoutine::amoptionalkey, IndexAmRoutine::amoptions, IndexAmRoutine::amparallelrescan, IndexAmRoutine::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->amcaninclude = false;
54  amroutine->amkeytype = InvalidOid;
55 
56  amroutine->ambuild = spgbuild;
57  amroutine->ambuildempty = spgbuildempty;
58  amroutine->aminsert = spginsert;
59  amroutine->ambulkdelete = spgbulkdelete;
60  amroutine->amvacuumcleanup = spgvacuumcleanup;
61  amroutine->amcanreturn = spgcanreturn;
62  amroutine->amcostestimate = spgcostestimate;
63  amroutine->amoptions = spgoptions;
64  amroutine->amproperty = NULL;
65  amroutine->amvalidate = spgvalidate;
66  amroutine->ambeginscan = spgbeginscan;
67  amroutine->amrescan = spgrescan;
68  amroutine->amgettuple = spggettuple;
69  amroutine->amgetbitmap = spggetbitmap;
70  amroutine->amendscan = spgendscan;
71  amroutine->ammarkpos = NULL;
72  amroutine->amrestrpos = NULL;
73  amroutine->amestimateparallelscan = NULL;
74  amroutine->aminitparallelscan = NULL;
75  amroutine->amparallelrescan = NULL;
76 
77  PG_RETURN_POINTER(amroutine);
78 }
ambeginscan_function ambeginscan
Definition: amapi.h:217
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:326
ambulkdelete_function ambulkdelete
Definition: amapi.h:210
bool amcanmulticol
Definition: amapi.h:180
uint16 amsupport
Definition: amapi.h:170
amgettuple_function amgettuple
Definition: amapi.h:219
bool amcanorderbyop
Definition: amapi.h:174
amproperty_function amproperty
Definition: amapi.h:215
IndexBulkDeleteResult * spgvacuumcleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats)
Definition: spgvacuum.c:932
amparallelrescan_function amparallelrescan
Definition: amapi.h:228
bool amstorage
Definition: amapi.h:188
void spgrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys, ScanKey orderbys, int norderbys)
Definition: spgscan.c:210
bool ampredlocks
Definition: amapi.h:192
aminsert_function aminsert
Definition: amapi.h:209
bool spginsert(Relation index, Datum *values, bool *isnull, ItemPointer ht_ctid, Relation heapRel, IndexUniqueCheck checkUnique, IndexInfo *indexInfo)
Definition: spginsert.c:215
Oid amkeytype
Definition: amapi.h:198
void spgendscan(IndexScanDesc scan)
Definition: spgscan.c:233
bool amoptionalkey
Definition: amapi.h:182
amvalidate_function amvalidate
Definition: amapi.h:216
bool spgcanreturn(Relation index, int attno)
Definition: spgscan.c:655
amgetbitmap_function amgetbitmap
Definition: amapi.h:220
IndexBulkDeleteResult * spgbulkdelete(IndexVacuumInfo *info, IndexBulkDeleteResult *stats, IndexBulkDeleteCallback callback, void *callback_state)
Definition: spgvacuum.c:901
ambuild_function ambuild
Definition: amapi.h:207
amoptions_function amoptions
Definition: amapi.h:214
bool amcaninclude
Definition: amapi.h:196
amcostestimate_function amcostestimate
Definition: amapi.h:213
bool amcanunique
Definition: amapi.h:178
amvacuumcleanup_function amvacuumcleanup
Definition: amapi.h:211
amendscan_function amendscan
Definition: amapi.h:221
bool amcanbackward
Definition: amapi.h:176
int64 spggetbitmap(IndexScanDesc scan, TIDBitmap *tbm)
Definition: spgscan.c:575
void spgbuildempty(Relation index)
Definition: spginsert.c:164
amrescan_function amrescan
Definition: amapi.h:218
bool amcanparallel
Definition: amapi.h:194
bytea * spgoptions(Datum reloptions, bool validate)
Definition: spgutils.c:581
bool amsearchnulls
Definition: amapi.h:186
bool amclusterable
Definition: amapi.h:190
bool amsearcharray
Definition: amapi.h:184
#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:7344
#define makeNode(_type_)
Definition: nodes.h:564
ammarkpos_function ammarkpos
Definition: amapi.h:222
bool amcanorder
Definition: amapi.h:172
amestimateparallelscan_function amestimateparallelscan
Definition: amapi.h:226
IndexBuildResult * spgbuild(Relation heap, Relation index, IndexInfo *indexInfo)
Definition: spginsert.c:74
uint16 amstrategies
Definition: amapi.h:168
#define SPGISTNProc
Definition: spgist.h:35
bool spgvalidate(Oid opclassoid)
Definition: spgvalidate.c:39
bool spggettuple(IndexScanDesc scan, ScanDirection dir)
Definition: spgscan.c:612
ambuildempty_function ambuildempty
Definition: amapi.h:208
IndexScanDesc spgbeginscan(Relation rel, int keysz, int orderbysz)
Definition: spgscan.c:181
amcanreturn_function amcanreturn
Definition: amapi.h:212
aminitparallelscan_function aminitparallelscan
Definition: amapi.h:227
amrestrpos_function amrestrpos
Definition: amapi.h:223

◆ SpGistGetBuffer()

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

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

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

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

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

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

◆ SpGistInitBuffer()

void SpGistInitBuffer ( Buffer  b,
uint16  f 
)

Definition at line 544 of file spgutils.c.

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

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

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

◆ SpGistInitMetapage()

void SpGistInitMetapage ( Page  page)

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

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

◆ SpGistInitPage()

void SpGistInitPage ( Page  page,
uint16  f 
)

Definition at line 529 of file spgutils.c.

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

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

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

◆ SpGistNewBuffer()

Buffer SpGistNewBuffer ( Relation  index)

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

206 {
207  Buffer buffer;
208  bool needLock;
209 
210  /* First, try to get a page from FSM */
211  for (;;)
212  {
213  BlockNumber blkno = GetFreeIndexPage(index);
214 
215  if (blkno == InvalidBlockNumber)
216  break; /* nothing known to FSM */
217 
218  /*
219  * The fixed pages shouldn't ever be listed in FSM, but just in case
220  * one is, ignore it.
221  */
222  if (SpGistBlockIsFixed(blkno))
223  continue;
224 
225  buffer = ReadBuffer(index, blkno);
226 
227  /*
228  * We have to guard against the possibility that someone else already
229  * recycled this page; the buffer may be locked if so.
230  */
231  if (ConditionalLockBuffer(buffer))
232  {
233  Page page = BufferGetPage(buffer);
234 
235  if (PageIsNew(page))
236  return buffer; /* OK to use, if never initialized */
237 
238  if (SpGistPageIsDeleted(page) || PageIsEmpty(page))
239  return buffer; /* OK to use */
240 
242  }
243 
244  /* Can't use it, so release buffer and try again */
245  ReleaseBuffer(buffer);
246  }
247 
248  /* Must extend the file */
249  needLock = !RELATION_IS_LOCAL(index);
250  if (needLock)
252 
253  buffer = ReadBuffer(index, P_NEW);
255 
256  if (needLock)
258 
259  return buffer;
260 }
#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:528
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 865 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().

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

495 {
496  SpGistCache *cache = spgGetCache(index);
497  SpGistLastUsedPage *lup;
498  int freeSpace;
499  Page page = BufferGetPage(buffer);
501  int flags;
502 
503  /* Never enter fixed pages (root pages) in cache, though */
504  if (SpGistBlockIsFixed(blkno))
505  return;
506 
507  if (SpGistPageIsLeaf(page))
508  flags = GBUF_LEAF;
509  else
510  flags = GBUF_INNER_PARITY(blkno);
511  if (SpGistPageStoresNulls(page))
512  flags |= GBUF_NULLS;
513 
514  lup = GET_LUP(cache, flags);
515 
516  freeSpace = PageGetExactFreeSpace(page);
517  if (lup->blkno == InvalidBlockNumber || lup->blkno == blkno ||
518  lup->freeSpace < freeSpace)
519  {
520  lup->blkno = blkno;
521  lup->freeSpace = freeSpace;
522  }
523 }
#define SpGistPageIsLeaf(page)
SpGistCache * spgGetCache(Relation index)
Definition: spgutils.c:93
#define GET_LUP(c, f)
Definition: spgutils.c:310
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 270 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().

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

◆ spgoptions()

bytea* spgoptions ( Datum  reloptions,
bool  validate 
)

Definition at line 581 of file spgutils.c.

References default_reloptions(), and RELOPT_KIND_SPGIST.

Referenced by spghandler().

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