PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
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

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

Definition at line 280 of file spgutils.c.

Referenced by SpGistGetBuffer(), and SpGistSetLastUsedPage().

Function Documentation

static Buffer allocNewBuffer ( Relation  index,
int  flags 
)
static

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

304 {
305  SpGistCache *cache = spgGetCache(index);
306  uint16 pageflags = 0;
307 
308  if (GBUF_REQ_LEAF(flags))
309  pageflags |= SPGIST_LEAF;
310  if (GBUF_REQ_NULLS(flags))
311  pageflags |= SPGIST_NULLS;
312 
313  for (;;)
314  {
315  Buffer buffer;
316 
317  buffer = SpGistNewBuffer(index);
318  SpGistInitBuffer(buffer, pageflags);
319 
320  if (pageflags & SPGIST_LEAF)
321  {
322  /* Leaf pages have no parity concerns, so just use it */
323  return buffer;
324  }
325  else
326  {
327  BlockNumber blkno = BufferGetBlockNumber(buffer);
328  int blkFlags = GBUF_INNER_PARITY(blkno);
329 
330  if ((flags & GBUF_PARITY_MASK) == blkFlags)
331  {
332  /* Page has right parity, use it */
333  return buffer;
334  }
335  else
336  {
337  /* Page has wrong parity, record it in cache and try again */
338  if (pageflags & SPGIST_NULLS)
339  blkFlags |= GBUF_NULLS;
340  cache->lastUsedPages.cachedPage[blkFlags].blkno = blkno;
341  cache->lastUsedPages.cachedPage[blkFlags].freeSpace =
343  UnlockReleaseBuffer(buffer);
344  }
345  }
346  }
347 }
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:267
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3332
#define GBUF_INNER_PARITY(x)
void SpGistInitBuffer(Buffer b, uint16 f)
Definition: spgutils.c:514
#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:633
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2605
#define SPGIST_LEAF
int Buffer
Definition: buf.h:23
#define GBUF_REQ_LEAF(flags)
static void fillTypeDesc ( SpGistTypeDesc desc,
Oid  type 
)
static

Definition at line 81 of file spgutils.c.

References SpGistTypeDesc::attbyval, SpGistTypeDesc::attlen, get_typlenbyval(), and SpGistTypeDesc::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:2001
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:404
spgConfigOut config
void * palloc0(Size size)
Definition: mcxt.c:878
char * deadTupleStorage
SpGistTypeDesc attLabelType
SpGistTypeDesc attPrefixType
static void memcpyDatum ( void *  target,
SpGistTypeDesc att,
Datum  datum 
)
static

Definition at line 573 of file spgutils.c.

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

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

574 {
575  unsigned int size;
576 
577  if (att->attbyval)
578  {
579  memcpy(target, &datum, sizeof(Datum));
580  }
581  else
582  {
583  size = (att->attlen > 0) ? att->attlen : VARSIZE_ANY(datum);
584  memcpy(target, DatumGetPointer(datum), size);
585  }
586 }
uintptr_t Datum
Definition: postgres.h:372
#define VARSIZE_ANY(PTR)
Definition: postgres.h:334
#define DatumGetPointer(X)
Definition: postgres.h:555
Datum* spgExtractNodeLabels ( SpGistState state,
SpGistInnerTuple  innerTuple 
)

Definition at line 784 of file spgutils.c.

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

Referenced by spgdoinsert(), and spgWalk().

785 {
786  Datum *nodeLabels;
787  int i;
788  SpGistNodeTuple node;
789 
790  /* Either all the labels must be NULL, or none. */
791  node = SGITNODEPTR(innerTuple);
792  if (IndexTupleHasNulls(node))
793  {
794  SGITITERATE(innerTuple, i, node)
795  {
796  if (!IndexTupleHasNulls(node))
797  elog(ERROR, "some but not all node labels are null in SPGiST inner tuple");
798  }
799  /* They're all null, so just return NULL */
800  return NULL;
801  }
802  else
803  {
804  nodeLabels = (Datum *) palloc(sizeof(Datum) * innerTuple->nNodes);
805  SGITITERATE(innerTuple, i, node)
806  {
807  if (IndexTupleHasNulls(node))
808  elog(ERROR, "some but not all node labels are null in SPGiST inner tuple");
809  nodeLabels[i] = SGNTDATUM(node, state);
810  }
811  return nodeLabels;
812  }
813 }
#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
#define NULL
Definition: c.h:229
void * palloc(Size size)
Definition: mcxt.c:849
int i
#define SGNTDATUM(x, s)
#define elog
Definition: elog.h:219
SpGistDeadTuple spgFormDeadTuple ( SpGistState state,
int  tupstate,
BlockNumber  blkno,
OffsetNumber  offnum 
)

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

756 {
758 
759  tuple->tupstate = tupstate;
760  tuple->size = SGDTSIZE;
762 
763  if (tupstate == SPGIST_REDIRECT)
764  {
765  ItemPointerSet(&tuple->pointer, blkno, offnum);
767  tuple->xid = state->myXid;
768  }
769  else
770  {
772  tuple->xid = InvalidTransactionId;
773  }
774 
775  return tuple;
776 }
#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:676
#define ItemPointerSetInvalid(pointer)
Definition: itemptr.h:150
#define TransactionIdIsValid(xid)
Definition: transam.h:41
#define ItemPointerSet(pointer, blockNumber, offNum)
Definition: itemptr.h:105
SpGistInnerTuple spgFormInnerTuple ( SpGistState state,
bool  hasPrefix,
Datum  prefix,
int  nNodes,
SpGistNodeTuple nodes 
)

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

673 {
674  SpGistInnerTuple tup;
675  unsigned int size;
676  unsigned int prefixSize;
677  int i;
678  char *ptr;
679 
680  /* Compute size needed */
681  if (hasPrefix)
682  prefixSize = SpGistGetTypeSize(&state->attPrefixType, prefix);
683  else
684  prefixSize = 0;
685 
686  size = SGITHDRSZ + prefixSize;
687 
688  /* Note: we rely on node tuple sizes to be maxaligned already */
689  for (i = 0; i < nNodes; i++)
690  size += IndexTupleSize(nodes[i]);
691 
692  /*
693  * Ensure that we can replace the tuple with a dead tuple later. This
694  * test is unnecessary given current tuple layouts, but let's be safe.
695  */
696  if (size < SGDTSIZE)
697  size = SGDTSIZE;
698 
699  /*
700  * Inner tuple should be small enough to fit on a page
701  */
702  if (size > SPGIST_PAGE_CAPACITY - sizeof(ItemIdData))
703  ereport(ERROR,
704  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
705  errmsg("SP-GiST inner tuple size %zu exceeds maximum %zu",
706  (Size) size,
707  SPGIST_PAGE_CAPACITY - sizeof(ItemIdData)),
708  errhint("Values larger than a buffer page cannot be indexed.")));
709 
710  /*
711  * Check for overflow of header fields --- probably can't fail if the
712  * above succeeded, but let's be paranoid
713  */
714  if (size > SGITMAXSIZE ||
715  prefixSize > SGITMAXPREFIXSIZE ||
716  nNodes > SGITMAXNNODES)
717  elog(ERROR, "SPGiST inner tuple header field is too small");
718 
719  /* OK, form the tuple */
720  tup = (SpGistInnerTuple) palloc0(size);
721 
722  tup->nNodes = nNodes;
723  tup->prefixSize = prefixSize;
724  tup->size = size;
725 
726  if (hasPrefix)
727  memcpyDatum(SGITDATAPTR(tup), &state->attPrefixType, prefix);
728 
729  ptr = (char *) SGITNODEPTR(tup);
730 
731  for (i = 0; i < nNodes; i++)
732  {
733  SpGistNodeTuple node = nodes[i];
734 
735  memcpy(ptr, node, IndexTupleSize(node));
736  ptr += IndexTupleSize(node);
737  }
738 
739  return tup;
740 }
#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:555
void * palloc0(Size size)
Definition: mcxt.c:878
#define SPGIST_PAGE_CAPACITY
size_t Size
Definition: c.h:356
static void memcpyDatum(void *target, SpGistTypeDesc *att, Datum datum)
Definition: spgutils.c:573
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
SpGistLeafTuple spgFormLeafTuple ( SpGistState state,
ItemPointer  heapPtr,
Datum  datum,
bool  isnull 
)

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

594 {
595  SpGistLeafTuple tup;
596  unsigned int size;
597 
598  /* compute space needed (note result is already maxaligned) */
599  size = SGLTHDRSZ;
600  if (!isnull)
601  size += SpGistGetTypeSize(&state->attType, datum);
602 
603  /*
604  * Ensure that we can replace the tuple with a dead tuple later. This
605  * test is unnecessary when !isnull, but let's be safe.
606  */
607  if (size < SGDTSIZE)
608  size = SGDTSIZE;
609 
610  /* OK, form the tuple */
611  tup = (SpGistLeafTuple) palloc0(size);
612 
613  tup->size = size;
615  tup->heapPtr = *heapPtr;
616  if (!isnull)
617  memcpyDatum(SGLTDATAPTR(tup), &state->attType, datum);
618 
619  return tup;
620 }
#define SGDTSIZE
SpGistTypeDesc attType
#define SGLTDATAPTR(x)
#define SGLTHDRSZ
unsigned int SpGistGetTypeSize(SpGistTypeDesc *att, Datum datum)
Definition: spgutils.c:555
void * palloc0(Size size)
Definition: mcxt.c:878
#define InvalidOffsetNumber
Definition: off.h:26
OffsetNumber nextOffset
static void memcpyDatum(void *target, SpGistTypeDesc *att, Datum datum)
Definition: spgutils.c:573
ItemPointerData heapPtr
SpGistLeafTupleData * SpGistLeafTuple
SpGistNodeTuple spgFormNodeTuple ( SpGistState state,
Datum  label,
bool  isnull 
)

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

630 {
631  SpGistNodeTuple tup;
632  unsigned int size;
633  unsigned short infomask = 0;
634 
635  /* compute space needed (note result is already maxaligned) */
636  size = SGNTHDRSZ;
637  if (!isnull)
638  size += SpGistGetTypeSize(&state->attLabelType, label);
639 
640  /*
641  * Here we make sure that the size will fit in the field reserved for it
642  * in t_info.
643  */
644  if ((size & INDEX_SIZE_MASK) != size)
645  ereport(ERROR,
646  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
647  errmsg("index row requires %zu bytes, maximum size is %zu",
648  (Size) size, (Size) INDEX_SIZE_MASK)));
649 
650  tup = (SpGistNodeTuple) palloc0(size);
651 
652  if (isnull)
653  infomask |= INDEX_NULL_MASK;
654  /* we don't bother setting the INDEX_VAR_MASK bit */
655  infomask |= size;
656  tup->t_info = infomask;
657 
658  /* The TID field will be filled in later */
660 
661  if (!isnull)
662  memcpyDatum(SGNTDATAPTR(tup), &state->attLabelType, label);
663 
664  return tup;
665 }
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:555
void * palloc0(Size size)
Definition: mcxt.c:878
static char * label
Definition: pg_basebackup.c:81
#define SGNTDATAPTR(x)
size_t Size
Definition: c.h:356
#define ItemPointerSetInvalid(pointer)
Definition: itemptr.h:150
static void memcpyDatum(void *target, SpGistTypeDesc *att, Datum datum)
Definition: spgutils.c:573
int errmsg(const char *fmt,...)
Definition: elog.c:797
unsigned short t_info
Definition: itup.h:49
SpGistNodeTupleData * SpGistNodeTuple
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, NULL, 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:84
Oid attType
Definition: spgist.h:40
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1047
unsigned int Oid
Definition: postgres_ext.h:31
SpGistTypeDesc attType
int natts
Definition: tupdesc.h:73
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:436
#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:742
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:676
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
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, NULL, 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:543
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:7111
#define makeNode(_type_)
Definition: nodes.h:557
#define NULL
Definition: c.h:229
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
Buffer SpGistGetBuffer ( Relation  index,
int  flags,
int  needSpace,
bool isNew 
)

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

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

Definition at line 555 of file spgutils.c.

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

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

556 {
557  unsigned int size;
558 
559  if (att->attbyval)
560  size = sizeof(Datum);
561  else if (att->attlen > 0)
562  size = att->attlen;
563  else
564  size = VARSIZE_ANY(datum);
565 
566  return MAXALIGN(size);
567 }
uintptr_t Datum
Definition: postgres.h:372
#define VARSIZE_ANY(PTR)
Definition: postgres.h:334
#define MAXALIGN(LEN)
Definition: c.h:588
void SpGistInitBuffer ( Buffer  b,
uint16  f 
)

Definition at line 514 of file spgutils.c.

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

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

515 {
516  Assert(BufferGetPageSize(b) == BLCKSZ);
518 }
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
#define BufferGetPageSize(buffer)
Definition: bufmgr.h:147
#define Assert(condition)
Definition: c.h:676
void SpGistInitPage(Page page, uint16 f)
Definition: spgutils.c:499
void SpGistInitMetapage ( Page  page)

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

525 {
526  SpGistMetaPageData *metadata;
527  int i;
528 
530  metadata = SpGistPageGetMeta(page);
531  memset(metadata, 0, sizeof(SpGistMetaPageData));
532  metadata->magicNumber = SPGIST_MAGIC_NUMBER;
533 
534  /* initialize last-used-page cache to empty */
535  for (i = 0; i < SPGIST_CACHED_PAGES; i++)
537 }
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:499
int i
void SpGistInitPage ( Page  page,
uint16  f 
)

Definition at line 499 of file spgutils.c.

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

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

500 {
501  SpGistPageOpaque opaque;
502 
503  PageInit(page, BLCKSZ, MAXALIGN(sizeof(SpGistPageOpaqueData)));
504  opaque = SpGistPageGetOpaque(page);
505  memset(opaque, 0, sizeof(SpGistPageOpaqueData));
506  opaque->flags = f;
507  opaque->spgist_page_id = SPGIST_PAGE_ID;
508 }
#define SPGIST_PAGE_ID
#define MAXALIGN(LEN)
Definition: c.h:588
#define SpGistPageGetOpaque(page)
void PageInit(Page page, Size pageSize, Size specialSize)
Definition: bufpage.c:41
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:523
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
OffsetNumber SpGistPageAddNewItem ( SpGistState state,
Page  page,
Item  item,
Size  size,
OffsetNumber startOffset,
bool  errorOK 
)

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

829 {
830  SpGistPageOpaque opaque = SpGistPageGetOpaque(page);
831  OffsetNumber i,
832  maxoff,
833  offnum;
834 
835  if (opaque->nPlaceholder > 0 &&
836  PageGetExactFreeSpace(page) + SGDTSIZE >= MAXALIGN(size))
837  {
838  /* Try to replace a placeholder */
839  maxoff = PageGetMaxOffsetNumber(page);
840  offnum = InvalidOffsetNumber;
841 
842  for (;;)
843  {
844  if (startOffset && *startOffset != InvalidOffsetNumber)
845  i = *startOffset;
846  else
847  i = FirstOffsetNumber;
848  for (; i <= maxoff; i++)
849  {
851  PageGetItemId(page, i));
852 
853  if (it->tupstate == SPGIST_PLACEHOLDER)
854  {
855  offnum = i;
856  break;
857  }
858  }
859 
860  /* Done if we found a placeholder */
861  if (offnum != InvalidOffsetNumber)
862  break;
863 
864  if (startOffset && *startOffset != InvalidOffsetNumber)
865  {
866  /* Hint was no good, re-search from beginning */
867  *startOffset = InvalidOffsetNumber;
868  continue;
869  }
870 
871  /* Hmm, no placeholder found? */
872  opaque->nPlaceholder = 0;
873  break;
874  }
875 
876  if (offnum != InvalidOffsetNumber)
877  {
878  /* Replace the placeholder tuple */
879  PageIndexTupleDelete(page, offnum);
880 
881  offnum = PageAddItem(page, item, size, offnum, false, false);
882 
883  /*
884  * We should not have failed given the size check at the top of
885  * the function, but test anyway. If we did fail, we must PANIC
886  * because we've already deleted the placeholder tuple, and
887  * there's no other way to keep the damage from getting to disk.
888  */
889  if (offnum != InvalidOffsetNumber)
890  {
891  Assert(opaque->nPlaceholder > 0);
892  opaque->nPlaceholder--;
893  if (startOffset)
894  *startOffset = offnum + 1;
895  }
896  else
897  elog(PANIC, "failed to add item of size %u to SPGiST index page",
898  (int) size);
899 
900  return offnum;
901  }
902  }
903 
904  /* No luck in replacing a placeholder, so just add it to the page */
905  offnum = PageAddItem(page, item, size,
906  InvalidOffsetNumber, false, false);
907 
908  if (offnum == InvalidOffsetNumber && !errorOK)
909  elog(ERROR, "failed to add item of size %u to SPGiST index page",
910  (int) size);
911 
912  return offnum;
913 }
#define SGDTSIZE
void PageIndexTupleDelete(Page page, OffsetNumber offnum)
Definition: bufpage.c:727
#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:676
#define MAXALIGN(LEN)
Definition: c.h:588
Size PageGetExactFreeSpace(Page page)
Definition: bufpage.c:633
#define SpGistPageGetOpaque(page)
int i
#define elog
Definition: elog.h:219
#define PageGetItem(page, itemId)
Definition: bufpage.h:336
void SpGistSetLastUsedPage ( Relation  index,
Buffer  buffer 
)

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

465 {
466  SpGistCache *cache = spgGetCache(index);
467  SpGistLastUsedPage *lup;
468  int freeSpace;
469  Page page = BufferGetPage(buffer);
471  int flags;
472 
473  /* Never enter fixed pages (root pages) in cache, though */
474  if (SpGistBlockIsFixed(blkno))
475  return;
476 
477  if (SpGistPageIsLeaf(page))
478  flags = GBUF_LEAF;
479  else
480  flags = GBUF_INNER_PARITY(blkno);
481  if (SpGistPageStoresNulls(page))
482  flags |= GBUF_NULLS;
483 
484  lup = GET_LUP(cache, flags);
485 
486  freeSpace = PageGetExactFreeSpace(page);
487  if (lup->blkno == InvalidBlockNumber || lup->blkno == blkno ||
488  lup->freeSpace < freeSpace)
489  {
490  lup->blkno = blkno;
491  lup->freeSpace = freeSpace;
492  }
493 }
#define SpGistPageIsLeaf(page)
SpGistCache * spgGetCache(Relation index)
Definition: spgutils.c:92
#define GET_LUP(c, f)
Definition: spgutils.c:280
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:633
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2605
Pointer Page
Definition: bufpage.h:74
void SpGistUpdateMetaPage ( Relation  index)

Definition at line 252 of file spgutils.c.

References BufferGetPage, ConditionalLockBuffer(), SpGistMetaPageData::lastUsedPages, SpGistCache::lastUsedPages, MarkBufferDirty(), NULL, 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  SpGistMetaPageData *metadata;
260 
261  metabuffer = ReadBuffer(index, SPGIST_METAPAGE_BLKNO);
262 
263  if (ConditionalLockBuffer(metabuffer))
264  {
265  metadata = SpGistPageGetMeta(BufferGetPage(metabuffer));
266  metadata->lastUsedPages = cache->lastUsedPages;
267 
268  MarkBufferDirty(metabuffer);
269  UnlockReleaseBuffer(metabuffer);
270  }
271  else
272  {
273  ReleaseBuffer(metabuffer);
274  }
275  }
276 }
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
#define NULL
Definition: c.h:229
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
bytea* spgoptions ( Datum  reloptions,
bool  validate 
)

Definition at line 543 of file spgutils.c.

References default_reloptions(), and RELOPT_KIND_SPGIST.

Referenced by spghandler().

544 {
545  return default_reloptions(reloptions, validate, RELOPT_KIND_SPGIST);
546 }
bytea * default_reloptions(Datum reloptions, bool validate, relopt_kind kind)
Definition: reloptions.c:1316