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

Referenced by SpGistGetBuffer(), and SpGistSetLastUsedPage().

Function Documentation

◆ allocNewBuffer()

static Buffer allocNewBuffer ( Relation  index,
int  flags 
)
static

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

316 {
317  SpGistCache *cache = spgGetCache(index);
318  uint16 pageflags = 0;
319 
320  if (GBUF_REQ_LEAF(flags))
321  pageflags |= SPGIST_LEAF;
322  if (GBUF_REQ_NULLS(flags))
323  pageflags |= SPGIST_NULLS;
324 
325  for (;;)
326  {
327  Buffer buffer;
328 
329  buffer = SpGistNewBuffer(index);
330  SpGistInitBuffer(buffer, pageflags);
331 
332  if (pageflags & SPGIST_LEAF)
333  {
334  /* Leaf pages have no parity concerns, so just use it */
335  return buffer;
336  }
337  else
338  {
339  BlockNumber blkno = BufferGetBlockNumber(buffer);
340  int blkFlags = GBUF_INNER_PARITY(blkno);
341 
342  if ((flags & GBUF_PARITY_MASK) == blkFlags)
343  {
344  /* Page has right parity, use it */
345  return buffer;
346  }
347  else
348  {
349  /* Page has wrong parity, record it in cache and try again */
350  if (pageflags & SPGIST_NULLS)
351  blkFlags |= GBUF_NULLS;
352  cache->lastUsedPages.cachedPage[blkFlags].blkno = blkno;
353  cache->lastUsedPages.cachedPage[blkFlags].freeSpace =
355  UnlockReleaseBuffer(buffer);
356  }
357  }
358  }
359 }
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:295
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3332
#define GBUF_INNER_PARITY(x)
void SpGistInitBuffer(Buffer b, uint16 f)
Definition: spgutils.c:526
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
Buffer SpGistNewBuffer(Relation index)
Definition: spgutils.c:187
#define GBUF_PARITY_MASK
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:214
#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:2020

◆ initSpGistState()

void initSpGistState ( SpGistState state,
Relation  index 
)

Definition at line 158 of file spgutils.c.

References SpGistState::attLabelType, SpGistCache::attLabelType, 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().

159 {
160  SpGistCache *cache;
161 
162  /* Get cached static information about index */
163  cache = spgGetCache(index);
164 
165  state->config = cache->config;
166  state->attType = cache->attType;
167  state->attPrefixType = cache->attPrefixType;
168  state->attLabelType = cache->attLabelType;
169 
170  /* Make workspace for constructing dead tuples */
172 
173  /* Set XID to use in redirection tuples */
174  state->myXid = GetTopTransactionIdIfAny();
175 
176  /* Assume we're not in an index build (spgbuild will override) */
177  state->isBuild = false;
178 }
SpGistTypeDesc attPrefixType
SpGistCache * spgGetCache(Relation index)
Definition: spgutils.c:92
#define SGDTSIZE
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:877
char * deadTupleStorage
SpGistTypeDesc attLabelType
SpGistTypeDesc attPrefixType

◆ memcpyDatum()

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

Definition at line 593 of file spgutils.c.

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

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

594 {
595  unsigned int size;
596 
597  if (att->attbyval)
598  {
599  memcpy(target, &datum, sizeof(Datum));
600  }
601  else
602  {
603  size = (att->attlen > 0) ? att->attlen : VARSIZE_ANY(datum);
604  memcpy(target, DatumGetPointer(datum), size);
605  }
606 }
uintptr_t Datum
Definition: postgres.h:372
#define VARSIZE_ANY(PTR)
Definition: postgres.h:334
#define DatumGetPointer(X)
Definition: postgres.h:555

◆ spgExtractNodeLabels()

Datum* spgExtractNodeLabels ( SpGistState state,
SpGistInnerTuple  innerTuple 
)

Definition at line 804 of file spgutils.c.

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

Referenced by spgdoinsert(), and spgWalk().

805 {
806  Datum *nodeLabels;
807  int i;
808  SpGistNodeTuple node;
809 
810  /* Either all the labels must be NULL, or none. */
811  node = SGITNODEPTR(innerTuple);
812  if (IndexTupleHasNulls(node))
813  {
814  SGITITERATE(innerTuple, i, node)
815  {
816  if (!IndexTupleHasNulls(node))
817  elog(ERROR, "some but not all node labels are null in SPGiST inner tuple");
818  }
819  /* They're all null, so just return NULL */
820  return NULL;
821  }
822  else
823  {
824  nodeLabels = (Datum *) palloc(sizeof(Datum) * innerTuple->nNodes);
825  SGITITERATE(innerTuple, i, node)
826  {
827  if (IndexTupleHasNulls(node))
828  elog(ERROR, "some but not all node labels are null in SPGiST inner tuple");
829  nodeLabels[i] = SGNTDATUM(node, state);
830  }
831  return nodeLabels;
832  }
833 }
#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:372
void * palloc(Size size)
Definition: mcxt.c:848
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 774 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().

776 {
778 
779  tuple->tupstate = tupstate;
780  tuple->size = SGDTSIZE;
782 
783  if (tupstate == SPGIST_REDIRECT)
784  {
785  ItemPointerSet(&tuple->pointer, blkno, offnum);
787  tuple->xid = state->myXid;
788  }
789  else
790  {
792  tuple->xid = InvalidTransactionId;
793  }
794 
795  return tuple;
796 }
#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:670
#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 691 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().

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

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

Referenced by doPickSplit(), and spgdoinsert().

614 {
615  SpGistLeafTuple tup;
616  unsigned int size;
617 
618  /* compute space needed (note result is already maxaligned) */
619  size = SGLTHDRSZ;
620  if (!isnull)
621  size += SpGistGetTypeSize(&state->attType, datum);
622 
623  /*
624  * Ensure that we can replace the tuple with a dead tuple later. This
625  * test is unnecessary when !isnull, but let's be safe.
626  */
627  if (size < SGDTSIZE)
628  size = SGDTSIZE;
629 
630  /* OK, form the tuple */
631  tup = (SpGistLeafTuple) palloc0(size);
632 
633  tup->size = size;
635  tup->heapPtr = *heapPtr;
636  if (!isnull)
637  memcpyDatum(SGLTDATAPTR(tup), &state->attType, datum);
638 
639  return tup;
640 }
#define SGDTSIZE
SpGistTypeDesc attType
#define SGLTDATAPTR(x)
#define SGLTHDRSZ
unsigned int SpGistGetTypeSize(SpGistTypeDesc *att, Datum datum)
Definition: spgutils.c:575
void * palloc0(Size size)
Definition: mcxt.c:877
#define InvalidOffsetNumber
Definition: off.h:26
OffsetNumber nextOffset
static void memcpyDatum(void *target, SpGistTypeDesc *att, Datum datum)
Definition: spgutils.c:593
ItemPointerData heapPtr
SpGistLeafTupleData * SpGistLeafTuple

◆ spgFormNodeTuple()

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

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

650 {
651  SpGistNodeTuple tup;
652  unsigned int size;
653  unsigned short infomask = 0;
654 
655  /* compute space needed (note result is already maxaligned) */
656  size = SGNTHDRSZ;
657  if (!isnull)
658  size += SpGistGetTypeSize(&state->attLabelType, label);
659 
660  /*
661  * Here we make sure that the size will fit in the field reserved for it
662  * in t_info.
663  */
664  if ((size & INDEX_SIZE_MASK) != size)
665  ereport(ERROR,
666  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
667  errmsg("index row requires %zu bytes, maximum size is %zu",
668  (Size) size, (Size) INDEX_SIZE_MASK)));
669 
670  tup = (SpGistNodeTuple) palloc0(size);
671 
672  if (isnull)
673  infomask |= INDEX_NULL_MASK;
674  /* we don't bother setting the INDEX_VAR_MASK bit */
675  infomask |= size;
676  tup->t_info = infomask;
677 
678  /* The TID field will be filled in later */
680 
681  if (!isnull)
682  memcpyDatum(SGNTDATAPTR(tup), &state->attLabelType, label);
683 
684  return tup;
685 }
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:575
void * palloc0(Size size)
Definition: mcxt.c:877
static char * label
Definition: pg_basebackup.c:82
#define SGNTDATAPTR(x)
size_t Size
Definition: c.h:404
#define ItemPointerSetInvalid(pointer)
Definition: itemptr.h:150
static void memcpyDatum(void *target, SpGistTypeDesc *att, Datum datum)
Definition: spgutils.c:593
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::attPrefixType, spgConfigIn::attType, SpGistCache::attType, BUFFER_LOCK_SHARE, BufferGetPage, SpGistCache::config, elog, ERROR, fillTypeDesc(), FunctionCall2Coll(), index_getprocinfo(), spgConfigOut::labelType, SpGistMetaPageData::lastUsedPages, SpGistCache::lastUsedPages, LockBuffer(), SpGistMetaPageData::magicNumber, MemoryContextAllocZero(), tupleDesc::natts, PointerGetDatum, spgConfigOut::prefixType, RelationData::rd_amcache, RelationData::rd_att, RelationData::rd_indcollation, RelationData::rd_indexcxt, ReadBuffer(), RelationGetRelationName, 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  fillTypeDesc(&cache->attPrefixType, cache->config.prefixType);
129  fillTypeDesc(&cache->attLabelType, cache->config.labelType);
130 
131  /* Last, get the lastUsedPages data from the metapage */
132  metabuffer = ReadBuffer(index, SPGIST_METAPAGE_BLKNO);
133  LockBuffer(metabuffer, BUFFER_LOCK_SHARE);
134 
135  metadata = SpGistPageGetMeta(BufferGetPage(metabuffer));
136 
137  if (metadata->magicNumber != SPGIST_MAGIC_NUMBER)
138  elog(ERROR, "index \"%s\" is not an SP-GiST index",
139  RelationGetRelationName(index));
140 
141  cache->lastUsedPages = metadata->lastUsedPages;
142 
143  UnlockReleaseBuffer(metabuffer);
144 
145  index->rd_amcache = (void *) cache;
146  }
147  else
148  {
149  /* assume it's up to date */
150  cache = (SpGistCache *) index->rd_amcache;
151  }
152 
153  return cache;
154 }
Definition: fmgr.h:56
FmgrInfo * index_getprocinfo(Relation irel, AttrNumber attnum, uint16 procnum)
Definition: indexam.c:855
#define PointerGetDatum(X)
Definition: postgres.h:562
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:90
Oid attType
Definition: spgist.h:40
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1042
unsigned int Oid
Definition: postgres_ext.h:31
SpGistTypeDesc attType
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 SPGIST_MAGIC_NUMBER
spgConfigOut config
SpGistLUPCache lastUsedPages
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3546
Oid prefixType
Definition: spgist.h:45
TupleDesc rd_att
Definition: rel.h:115
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:741
#define Assert(condition)
Definition: c.h:670
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:594
#define SPGIST_CONFIG_PROC
Definition: spgist.h:28
#define SpGistPageGetMeta(p)
SpGistTypeDesc attLabelType
MemoryContext rd_indexcxt
Definition: rel.h:179
Oid labelType
Definition: spgist.h:46
#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

◆ 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:208
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:157
amrescan_function amrescan
Definition: amapi.h:209
bool amcanparallel
Definition: amapi.h:193
bytea * spgoptions(Datum reloptions, bool validate)
Definition: spgutils.c:563
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:560
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:33
bool spgvalidate(Oid opclassoid)
Definition: spgvalidate.c:38
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 371 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().

372 {
373  SpGistCache *cache = spgGetCache(index);
374  SpGistLastUsedPage *lup;
375 
376  /* Bail out if even an empty page wouldn't meet the demand */
377  if (needSpace > SPGIST_PAGE_CAPACITY)
378  elog(ERROR, "desired SPGiST tuple size is too big");
379 
380  /*
381  * If possible, increase the space request to include relation's
382  * fillfactor. This ensures that when we add unrelated tuples to a page,
383  * we try to keep 100-fillfactor% available for adding tuples that are
384  * related to the ones already on it. But fillfactor mustn't cause an
385  * error for requests that would otherwise be legal.
386  */
387  needSpace += RelationGetTargetPageFreeSpace(index,
389  needSpace = Min(needSpace, SPGIST_PAGE_CAPACITY);
390 
391  /* Get the cache entry for this flags setting */
392  lup = GET_LUP(cache, flags);
393 
394  /* If we have nothing cached, just turn it over to allocNewBuffer */
395  if (lup->blkno == InvalidBlockNumber)
396  {
397  *isNew = true;
398  return allocNewBuffer(index, flags);
399  }
400 
401  /* fixed pages should never be in cache */
403 
404  /* If cached freeSpace isn't enough, don't bother looking at the page */
405  if (lup->freeSpace >= needSpace)
406  {
407  Buffer buffer;
408  Page page;
409 
410  buffer = ReadBuffer(index, lup->blkno);
411 
412  if (!ConditionalLockBuffer(buffer))
413  {
414  /*
415  * buffer is locked by another process, so return a new buffer
416  */
417  ReleaseBuffer(buffer);
418  *isNew = true;
419  return allocNewBuffer(index, flags);
420  }
421 
422  page = BufferGetPage(buffer);
423 
424  if (PageIsNew(page) || SpGistPageIsDeleted(page) || PageIsEmpty(page))
425  {
426  /* OK to initialize the page */
427  uint16 pageflags = 0;
428 
429  if (GBUF_REQ_LEAF(flags))
430  pageflags |= SPGIST_LEAF;
431  if (GBUF_REQ_NULLS(flags))
432  pageflags |= SPGIST_NULLS;
433  SpGistInitBuffer(buffer, pageflags);
434  lup->freeSpace = PageGetExactFreeSpace(page) - needSpace;
435  *isNew = true;
436  return buffer;
437  }
438 
439  /*
440  * Check that page is of right type and has enough space. We must
441  * recheck this since our cache isn't necessarily up to date.
442  */
443  if ((GBUF_REQ_LEAF(flags) ? SpGistPageIsLeaf(page) : !SpGistPageIsLeaf(page)) &&
445  {
446  int freeSpace = PageGetExactFreeSpace(page);
447 
448  if (freeSpace >= needSpace)
449  {
450  /* Success, update freespace info and return the buffer */
451  lup->freeSpace = freeSpace - needSpace;
452  *isNew = false;
453  return buffer;
454  }
455  }
456 
457  /*
458  * fallback to allocation of new buffer
459  */
460  UnlockReleaseBuffer(buffer);
461  }
462 
463  /* No success with cache, so return a new buffer */
464  *isNew = true;
465  return allocNewBuffer(index, flags);
466 }
#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:292
#define Min(x, y)
Definition: c.h:802
#define SPGIST_NULLS
static Buffer allocNewBuffer(Relation index, int flags)
Definition: spgutils.c:315
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:295
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:526
#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:670
#define SpGistPageIsDeleted(page)
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:214
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 575 of file spgutils.c.

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

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

576 {
577  unsigned int size;
578 
579  if (att->attbyval)
580  size = sizeof(Datum);
581  else if (att->attlen > 0)
582  size = att->attlen;
583  else
584  size = VARSIZE_ANY(datum);
585 
586  return MAXALIGN(size);
587 }
uintptr_t Datum
Definition: postgres.h:372
#define VARSIZE_ANY(PTR)
Definition: postgres.h:334
#define MAXALIGN(LEN)
Definition: c.h:623

◆ SpGistInitBuffer()

void SpGistInitBuffer ( Buffer  b,
uint16  f 
)

Definition at line 526 of file spgutils.c.

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

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

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

◆ SpGistInitMetapage()

void SpGistInitMetapage ( Page  page)

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

537 {
538  SpGistMetaPageData *metadata;
539  int i;
540 
542  metadata = SpGistPageGetMeta(page);
543  memset(metadata, 0, sizeof(SpGistMetaPageData));
544  metadata->magicNumber = SPGIST_MAGIC_NUMBER;
545 
546  /* initialize last-used-page cache to empty */
547  for (i = 0; i < SPGIST_CACHED_PAGES; i++)
549 
550  /*
551  * Set pd_lower just past the end of the metadata. This is essential,
552  * because without doing so, metadata will be lost if xlog.c compresses
553  * the page.
554  */
555  ((PageHeader) page)->pd_lower =
556  ((char *) metadata + sizeof(SpGistMetaPageData)) - (char *) page;
557 }
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:511
int i

◆ SpGistInitPage()

void SpGistInitPage ( Page  page,
uint16  f 
)

Definition at line 511 of file spgutils.c.

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

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

512 {
513  SpGistPageOpaque opaque;
514 
515  PageInit(page, BLCKSZ, MAXALIGN(sizeof(SpGistPageOpaqueData)));
516  opaque = SpGistPageGetOpaque(page);
517  memset(opaque, 0, sizeof(SpGistPageOpaqueData));
518  opaque->flags = f;
519  opaque->spgist_page_id = SPGIST_PAGE_ID;
520 }
#define SPGIST_PAGE_ID
#define MAXALIGN(LEN)
Definition: c.h:623
#define SpGistPageGetOpaque(page)
void PageInit(Page page, Size pageSize, Size specialSize)
Definition: bufpage.c:41

◆ SpGistNewBuffer()

Buffer SpGistNewBuffer ( Relation  index)

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

188 {
189  Buffer buffer;
190  bool needLock;
191 
192  /* First, try to get a page from FSM */
193  for (;;)
194  {
195  BlockNumber blkno = GetFreeIndexPage(index);
196 
197  if (blkno == InvalidBlockNumber)
198  break; /* nothing known to FSM */
199 
200  /*
201  * The fixed pages shouldn't ever be listed in FSM, but just in case
202  * one is, ignore it.
203  */
204  if (SpGistBlockIsFixed(blkno))
205  continue;
206 
207  buffer = ReadBuffer(index, blkno);
208 
209  /*
210  * We have to guard against the possibility that someone else already
211  * recycled this page; the buffer may be locked if so.
212  */
213  if (ConditionalLockBuffer(buffer))
214  {
215  Page page = BufferGetPage(buffer);
216 
217  if (PageIsNew(page))
218  return buffer; /* OK to use, if never initialized */
219 
220  if (SpGistPageIsDeleted(page) || PageIsEmpty(page))
221  return buffer; /* OK to use */
222 
224  }
225 
226  /* Can't use it, so release buffer and try again */
227  ReleaseBuffer(buffer);
228  }
229 
230  /* Must extend the file */
231  needLock = !RELATION_IS_LOCAL(index);
232  if (needLock)
234 
235  buffer = ReadBuffer(index, P_NEW);
237 
238  if (needLock)
240 
241  return buffer;
242 }
#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:214
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 847 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().

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

477 {
478  SpGistCache *cache = spgGetCache(index);
479  SpGistLastUsedPage *lup;
480  int freeSpace;
481  Page page = BufferGetPage(buffer);
483  int flags;
484 
485  /* Never enter fixed pages (root pages) in cache, though */
486  if (SpGistBlockIsFixed(blkno))
487  return;
488 
489  if (SpGistPageIsLeaf(page))
490  flags = GBUF_LEAF;
491  else
492  flags = GBUF_INNER_PARITY(blkno);
493  if (SpGistPageStoresNulls(page))
494  flags |= GBUF_NULLS;
495 
496  lup = GET_LUP(cache, flags);
497 
498  freeSpace = PageGetExactFreeSpace(page);
499  if (lup->blkno == InvalidBlockNumber || lup->blkno == blkno ||
500  lup->freeSpace < freeSpace)
501  {
502  lup->blkno = blkno;
503  lup->freeSpace = freeSpace;
504  }
505 }
#define SpGistPageIsLeaf(page)
SpGistCache * spgGetCache(Relation index)
Definition: spgutils.c:92
#define GET_LUP(c, f)
Definition: spgutils.c:292
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:214
#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 252 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().

253 {
254  SpGistCache *cache = (SpGistCache *) index->rd_amcache;
255 
256  if (cache != NULL)
257  {
258  Buffer metabuffer;
259 
260  metabuffer = ReadBuffer(index, SPGIST_METAPAGE_BLKNO);
261 
262  if (ConditionalLockBuffer(metabuffer))
263  {
264  Page metapage = BufferGetPage(metabuffer);
265  SpGistMetaPageData *metadata = SpGistPageGetMeta(metapage);
266 
267  metadata->lastUsedPages = cache->lastUsedPages;
268 
269  /*
270  * Set pd_lower just past the end of the metadata. This is
271  * essential, because without doing so, metadata will be lost if
272  * xlog.c compresses the page. (We must do this here because
273  * pre-v11 versions of PG did not set the metapage's pd_lower
274  * correctly, so a pg_upgraded index might contain the wrong
275  * value.)
276  */
277  ((PageHeader) metapage)->pd_lower =
278  ((char *) metadata + sizeof(SpGistMetaPageData)) - (char *) metapage;
279 
280  MarkBufferDirty(metabuffer);
281  UnlockReleaseBuffer(metabuffer);
282  }
283  else
284  {
285  ReleaseBuffer(metabuffer);
286  }
287  }
288 }
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 563 of file spgutils.c.

References default_reloptions(), and RELOPT_KIND_SPGIST.

Referenced by spghandler().

564 {
565  return default_reloptions(reloptions, validate, RELOPT_KIND_SPGIST);
566 }
bytea * default_reloptions(Datum reloptions, bool validate, relopt_kind kind)
Definition: reloptions.c:1326