PostgreSQL Source Code  git master
spgist_private.h File Reference
#include "access/itup.h"
#include "access/spgist.h"
#include "nodes/tidbitmap.h"
#include "storage/buf.h"
#include "utils/relcache.h"
Include dependency graph for spgist_private.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  SpGistPageOpaqueData
 
struct  SpGistLastUsedPage
 
struct  SpGistLUPCache
 
struct  SpGistMetaPageData
 
struct  SpGistTypeDesc
 
struct  SpGistState
 
struct  SpGistScanOpaqueData
 
struct  SpGistCache
 
struct  SpGistInnerTupleData
 
struct  SpGistLeafTupleData
 
struct  SpGistDeadTupleData
 

Macros

#define SPGIST_METAPAGE_BLKNO   (0) /* metapage */
 
#define SPGIST_ROOT_BLKNO   (1) /* root for normal entries */
 
#define SPGIST_NULL_BLKNO   (2) /* root for null-value entries */
 
#define SPGIST_LAST_FIXED_BLKNO   SPGIST_NULL_BLKNO
 
#define SpGistBlockIsRoot(blkno)   ((blkno) == SPGIST_ROOT_BLKNO || (blkno) == SPGIST_NULL_BLKNO)
 
#define SpGistBlockIsFixed(blkno)   ((BlockNumber) (blkno) <= (BlockNumber) SPGIST_LAST_FIXED_BLKNO)
 
#define SPGIST_META   (1<<0)
 
#define SPGIST_DELETED
 
#define SPGIST_LEAF   (1<<2)
 
#define SPGIST_NULLS   (1<<3)
 
#define SpGistPageGetOpaque(page)   ((SpGistPageOpaque) PageGetSpecialPointer(page))
 
#define SpGistPageIsMeta(page)   (SpGistPageGetOpaque(page)->flags & SPGIST_META)
 
#define SpGistPageIsDeleted(page)   (SpGistPageGetOpaque(page)->flags & SPGIST_DELETED)
 
#define SpGistPageIsLeaf(page)   (SpGistPageGetOpaque(page)->flags & SPGIST_LEAF)
 
#define SpGistPageStoresNulls(page)   (SpGistPageGetOpaque(page)->flags & SPGIST_NULLS)
 
#define SPGIST_PAGE_ID   0xFF82
 
#define SPGIST_CACHED_PAGES   8
 
#define SPGIST_MAGIC_NUMBER   (0xBA0BABEE)
 
#define SpGistPageGetMeta(p)   ((SpGistMetaPageData *) PageGetContents(p))
 
#define SPGIST_LIVE   0 /* normal live tuple (either inner or leaf) */
 
#define SPGIST_REDIRECT   1 /* temporary redirection placeholder */
 
#define SPGIST_DEAD   2 /* dead, cannot be removed because of links */
 
#define SPGIST_PLACEHOLDER   3 /* placeholder, used to preserve offsets */
 
#define SGITMAXNNODES   0x1FFF
 
#define SGITMAXPREFIXSIZE   0xFFFF
 
#define SGITMAXSIZE   0xFFFF
 
#define SGITHDRSZ   MAXALIGN(sizeof(SpGistInnerTupleData))
 
#define _SGITDATA(x)   (((char *) (x)) + SGITHDRSZ)
 
#define SGITDATAPTR(x)   ((x)->prefixSize ? _SGITDATA(x) : NULL)
 
#define SGITDATUM(x, s)
 
#define SGITNODEPTR(x)   ((SpGistNodeTuple) (_SGITDATA(x) + (x)->prefixSize))
 
#define SGITITERATE(x, i, nt)
 
#define SGNTHDRSZ   MAXALIGN(sizeof(SpGistNodeTupleData))
 
#define SGNTDATAPTR(x)   (((char *) (x)) + SGNTHDRSZ)
 
#define SGNTDATUM(x, s)
 
#define SGLTHDRSZ   MAXALIGN(sizeof(SpGistLeafTupleData))
 
#define SGLTDATAPTR(x)   (((char *) (x)) + SGLTHDRSZ)
 
#define SGLTDATUM(x, s)
 
#define SGDTSIZE   MAXALIGN(sizeof(SpGistDeadTupleData))
 
#define SPGIST_PAGE_CAPACITY
 
#define SpGistPageGetFreeSpace(p, n)
 
#define STORE_STATE(s, d)
 
#define GBUF_LEAF   0x03
 
#define GBUF_INNER_PARITY(x)   ((x) % 3)
 
#define GBUF_NULLS   0x04
 
#define GBUF_PARITY_MASK   0x03
 
#define GBUF_REQ_LEAF(flags)   (((flags) & GBUF_PARITY_MASK) == GBUF_LEAF)
 
#define GBUF_REQ_NULLS(flags)   ((flags) & GBUF_NULLS)
 

Typedefs

typedef struct SpGistPageOpaqueData SpGistPageOpaqueData
 
typedef SpGistPageOpaqueDataSpGistPageOpaque
 
typedef struct SpGistLastUsedPage SpGistLastUsedPage
 
typedef struct SpGistLUPCache SpGistLUPCache
 
typedef struct SpGistMetaPageData SpGistMetaPageData
 
typedef struct SpGistTypeDesc SpGistTypeDesc
 
typedef struct SpGistState SpGistState
 
typedef struct SpGistScanOpaqueData SpGistScanOpaqueData
 
typedef SpGistScanOpaqueDataSpGistScanOpaque
 
typedef struct SpGistCache SpGistCache
 
typedef struct SpGistInnerTupleData SpGistInnerTupleData
 
typedef SpGistInnerTupleDataSpGistInnerTuple
 
typedef IndexTupleData SpGistNodeTupleData
 
typedef SpGistNodeTupleDataSpGistNodeTuple
 
typedef struct SpGistLeafTupleData SpGistLeafTupleData
 
typedef SpGistLeafTupleDataSpGistLeafTuple
 
typedef struct SpGistDeadTupleData SpGistDeadTupleData
 
typedef SpGistDeadTupleDataSpGistDeadTuple
 

Functions

SpGistCachespgGetCache (Relation index)
 
void initSpGistState (SpGistState *state, Relation index)
 
Buffer SpGistNewBuffer (Relation index)
 
void SpGistUpdateMetaPage (Relation index)
 
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)
 
unsigned int SpGistGetTypeSize (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)
 
void spgUpdateNodeLink (SpGistInnerTuple tup, int nodeN, BlockNumber blkno, OffsetNumber offset)
 
void spgPageIndexMultiDelete (SpGistState *state, Page page, OffsetNumber *itemnos, int nitems, int firststate, int reststate, BlockNumber blkno, OffsetNumber offnum)
 
bool spgdoinsert (Relation index, SpGistState *state, ItemPointer heapPtr, Datum datum, bool isnull)
 

Macro Definition Documentation

◆ _SGITDATA

#define _SGITDATA (   x)    (((char *) (x)) + SGITHDRSZ)

Definition at line 232 of file spgist_private.h.

◆ GBUF_INNER_PARITY

#define GBUF_INNER_PARITY (   x)    ((x) % 3)

◆ GBUF_LEAF

#define GBUF_LEAF   0x03

Definition at line 377 of file spgist_private.h.

Referenced by doPickSplit(), moveLeafs(), spgdoinsert(), and SpGistSetLastUsedPage().

◆ GBUF_NULLS

#define GBUF_NULLS   0x04

◆ GBUF_PARITY_MASK

#define GBUF_PARITY_MASK   0x03

Definition at line 381 of file spgist_private.h.

Referenced by allocNewBuffer().

◆ GBUF_REQ_LEAF

#define GBUF_REQ_LEAF (   flags)    (((flags) & GBUF_PARITY_MASK) == GBUF_LEAF)

Definition at line 382 of file spgist_private.h.

Referenced by allocNewBuffer(), and SpGistGetBuffer().

◆ GBUF_REQ_NULLS

#define GBUF_REQ_NULLS (   flags)    ((flags) & GBUF_NULLS)

Definition at line 383 of file spgist_private.h.

Referenced by allocNewBuffer(), and SpGistGetBuffer().

◆ SGDTSIZE

◆ SGITDATAPTR

#define SGITDATAPTR (   x)    ((x)->prefixSize ? _SGITDATA(x) : NULL)

Definition at line 233 of file spgist_private.h.

Referenced by spgFormInnerTuple().

◆ SGITDATUM

#define SGITDATUM (   x,
 
)
Value:
((x)->prefixSize ? \
((s)->attPrefixType.attbyval ? \
*(Datum *) _SGITDATA(x) : \
PointerGetDatum(_SGITDATA(x))) \
: (Datum) 0)
#define _SGITDATA(x)
uintptr_t Datum
Definition: postgres.h:367

Definition at line 234 of file spgist_private.h.

Referenced by addNode(), spgdoinsert(), and spgWalk().

◆ SGITHDRSZ

#define SGITHDRSZ   MAXALIGN(sizeof(SpGistInnerTupleData))

Definition at line 231 of file spgist_private.h.

Referenced by spgFormInnerTuple().

◆ SGITITERATE

#define SGITITERATE (   x,
  i,
  nt 
)
Value:
for ((i) = 0, (nt) = SGITNODEPTR(x); \
(i) < (x)->nNodes; \
(i)++, (nt) = (SpGistNodeTuple) (((char *) (nt)) + IndexTupleSize(nt)))
#define SGITNODEPTR(x)
int i
#define IndexTupleSize(itup)
Definition: itup.h:71
SpGistNodeTupleData * SpGistNodeTuple

Definition at line 242 of file spgist_private.h.

Referenced by addNode(), doPickSplit(), spgExtractNodeLabels(), spgMatchNodeAction(), spgprocesspending(), spgSplitNodeAction(), spgUpdateNodeLink(), and spgWalk().

◆ SGITMAXNNODES

#define SGITMAXNNODES   0x1FFF

Definition at line 227 of file spgist_private.h.

Referenced by spgFormInnerTuple(), and spgSplitNodeAction().

◆ SGITMAXPREFIXSIZE

#define SGITMAXPREFIXSIZE   0xFFFF

Definition at line 228 of file spgist_private.h.

Referenced by spgFormInnerTuple().

◆ SGITMAXSIZE

#define SGITMAXSIZE   0xFFFF

Definition at line 229 of file spgist_private.h.

Referenced by spgFormInnerTuple().

◆ SGITNODEPTR

#define SGITNODEPTR (   x)    ((SpGistNodeTuple) (_SGITDATA(x) + (x)->prefixSize))

Definition at line 239 of file spgist_private.h.

Referenced by spgExtractNodeLabels(), and spgFormInnerTuple().

◆ SGLTDATAPTR

#define SGLTDATAPTR (   x)    (((char *) (x)) + SGLTHDRSZ)

Definition at line 305 of file spgist_private.h.

Referenced by spgFormLeafTuple().

◆ SGLTDATUM

#define SGLTDATUM (   x,
 
)
Value:
((s)->attLeafType.attbyval ? \
*(Datum *) SGLTDATAPTR(x) : \
#define PointerGetDatum(X)
Definition: postgres.h:541
#define SGLTDATAPTR(x)
uintptr_t Datum
Definition: postgres.h:367

Definition at line 306 of file spgist_private.h.

Referenced by doPickSplit(), and spgLeafTest().

◆ SGLTHDRSZ

#define SGLTHDRSZ   MAXALIGN(sizeof(SpGistLeafTupleData))

Definition at line 304 of file spgist_private.h.

Referenced by spgdoinsert(), and spgFormLeafTuple().

◆ SGNTDATAPTR

#define SGNTDATAPTR (   x)    (((char *) (x)) + SGNTHDRSZ)

Definition at line 262 of file spgist_private.h.

Referenced by spgFormNodeTuple().

◆ SGNTDATUM

#define SGNTDATUM (   x,
 
)
Value:
((s)->attLabelType.attbyval ? \
*(Datum *) SGNTDATAPTR(x) : \
#define PointerGetDatum(X)
Definition: postgres.h:541
uintptr_t Datum
Definition: postgres.h:367
#define SGNTDATAPTR(x)

Definition at line 263 of file spgist_private.h.

Referenced by spgExtractNodeLabels().

◆ SGNTHDRSZ

#define SGNTHDRSZ   MAXALIGN(sizeof(SpGistNodeTupleData))

Definition at line 261 of file spgist_private.h.

Referenced by spgFormNodeTuple().

◆ SPGIST_CACHED_PAGES

#define SPGIST_CACHED_PAGES   8

Definition at line 84 of file spgist_private.h.

Referenced by SpGistInitMetapage().

◆ SPGIST_DEAD

#define SPGIST_DEAD   2 /* dead, cannot be removed because of links */

◆ SPGIST_DELETED

#define SPGIST_DELETED
Value:
(1<<1) /* never set, but keep for backwards
* compatibility */

Definition at line 51 of file spgist_private.h.

◆ SPGIST_LAST_FIXED_BLKNO

#define SPGIST_LAST_FIXED_BLKNO   SPGIST_NULL_BLKNO

Definition at line 28 of file spgist_private.h.

Referenced by spgvacuumscan().

◆ SPGIST_LEAF

◆ SPGIST_LIVE

#define SPGIST_LIVE   0 /* normal live tuple (either inner or leaf) */

◆ SPGIST_MAGIC_NUMBER

#define SPGIST_MAGIC_NUMBER   (0xBA0BABEE)

Definition at line 100 of file spgist_private.h.

Referenced by spgGetCache(), and SpGistInitMetapage().

◆ SPGIST_META

#define SPGIST_META   (1<<0)

Definition at line 50 of file spgist_private.h.

Referenced by SpGistInitMetapage().

◆ SPGIST_METAPAGE_BLKNO

#define SPGIST_METAPAGE_BLKNO   (0) /* metapage */

◆ SPGIST_NULL_BLKNO

#define SPGIST_NULL_BLKNO   (2) /* root for null-value entries */

◆ SPGIST_NULLS

◆ SPGIST_PAGE_CAPACITY

#define SPGIST_PAGE_CAPACITY
Value:
MAXALIGN_DOWN(BLCKSZ - \
#define SizeOfPageHeaderData
Definition: bufpage.h:212
#define MAXALIGN(LEN)
Definition: c.h:652
#define MAXALIGN_DOWN(LEN)
Definition: c.h:664

Definition at line 342 of file spgist_private.h.

Referenced by doPickSplit(), spgdoinsert(), spgFormInnerTuple(), and SpGistGetBuffer().

◆ SPGIST_PAGE_ID

#define SPGIST_PAGE_ID   0xFF82

Definition at line 70 of file spgist_private.h.

Referenced by SpGistInitPage().

◆ SPGIST_PLACEHOLDER

◆ SPGIST_REDIRECT

◆ SPGIST_ROOT_BLKNO

#define SPGIST_ROOT_BLKNO   (1) /* root for normal entries */

◆ SpGistBlockIsFixed

#define SpGistBlockIsFixed (   blkno)    ((BlockNumber) (blkno) <= (BlockNumber) SPGIST_LAST_FIXED_BLKNO)

Definition at line 32 of file spgist_private.h.

Referenced by SpGistGetBuffer(), SpGistNewBuffer(), and SpGistSetLastUsedPage().

◆ SpGistBlockIsRoot

#define SpGistBlockIsRoot (   blkno)    ((blkno) == SPGIST_ROOT_BLKNO || (blkno) == SPGIST_NULL_BLKNO)

◆ SpGistPageGetFreeSpace

#define SpGistPageGetFreeSpace (   p,
 
)
Value:
Min(SpGistPageGetOpaque(p)->nPlaceholder, n) * \
(SGDTSIZE + sizeof(ItemIdData)))
#define SGDTSIZE
struct ItemIdData ItemIdData
Size PageGetExactFreeSpace(Page page)
Definition: bufpage.c:629
#define SpGistPageGetOpaque(page)

Definition at line 351 of file spgist_private.h.

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

◆ SpGistPageGetMeta

#define SpGistPageGetMeta (   p)    ((SpGistMetaPageData *) PageGetContents(p))

Definition at line 102 of file spgist_private.h.

Referenced by spgGetCache(), SpGistInitMetapage(), and SpGistUpdateMetaPage().

◆ SpGistPageGetOpaque

◆ SpGistPageIsDeleted

#define SpGistPageIsDeleted (   page)    (SpGistPageGetOpaque(page)->flags & SPGIST_DELETED)

Definition at line 58 of file spgist_private.h.

Referenced by SpGistGetBuffer(), SpGistNewBuffer(), and spgprocesspending().

◆ SpGistPageIsLeaf

#define SpGistPageIsLeaf (   page)    (SpGistPageGetOpaque(page)->flags & SPGIST_LEAF)

◆ SpGistPageIsMeta

#define SpGistPageIsMeta (   page)    (SpGistPageGetOpaque(page)->flags & SPGIST_META)

Definition at line 57 of file spgist_private.h.

◆ SpGistPageStoresNulls

#define SpGistPageStoresNulls (   page)    (SpGistPageGetOpaque(page)->flags & SPGIST_NULLS)

◆ STORE_STATE

#define STORE_STATE (   s,
 
)
Value:
do { \
(d).myXid = (s)->myXid; \
(d).isBuild = (s)->isBuild; \
} while(0)

Definition at line 360 of file spgist_private.h.

Referenced by doPickSplit(), moveLeafs(), spgAddNodeAction(), vacuumLeafPage(), and vacuumLeafRoot().

Typedef Documentation

◆ SpGistCache

◆ SpGistDeadTuple

◆ SpGistDeadTupleData

◆ SpGistInnerTuple

◆ SpGistInnerTupleData

◆ SpGistLastUsedPage

◆ SpGistLeafTuple

◆ SpGistLeafTupleData

◆ SpGistLUPCache

◆ SpGistMetaPageData

◆ SpGistNodeTuple

◆ SpGistNodeTupleData

◆ SpGistPageOpaque

◆ SpGistPageOpaqueData

◆ SpGistScanOpaque

◆ SpGistScanOpaqueData

◆ SpGistState

◆ SpGistTypeDesc

Function Documentation

◆ initSpGistState()

void initSpGistState ( SpGistState state,
Relation  index 
)

Definition at line 175 of file spgutils.c.

References SpGistState::attLabelType, SpGistCache::attLabelType, SpGistState::attLeafType, SpGistCache::attLeafType, SpGistState::attPrefixType, SpGistCache::attPrefixType, SpGistState::attType, SpGistCache::attType, SpGistState::config, SpGistCache::config, SpGistState::deadTupleStorage, GetTopTransactionIdIfAny(), SpGistState::isBuild, SpGistState::myXid, palloc0(), SGDTSIZE, and spgGetCache().

Referenced by spgbeginscan(), spgbuild(), spginsert(), and spgvacuumscan().

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

◆ spgdoinsert()

bool spgdoinsert ( Relation  index,
SpGistState state,
ItemPointer  heapPtr,
Datum  datum,
bool  isnull 
)

Definition at line 1891 of file spgdoinsert.c.

References addLeafTuple(), spgChooseOut::addNode, spgChooseIn::allTheSame, SpGistInnerTupleData::allTheSame, Assert, SpGistState::attLeafType, SpGistTypeDesc::attlen, SpGistState::attType, SPPageDesc::blkno, SPPageDesc::buffer, BUFFER_LOCK_EXCLUSIVE, BufferGetBlockNumber(), BufferGetPage, CHECK_FOR_INTERRUPTS, checkSplitConditions(), ConditionalLockBuffer(), SpGistState::config, spgChooseIn::datum, doPickSplit(), elog, ereport, errcode(), errhint(), errmsg(), ERROR, FirstOffsetNumber, FunctionCall1Coll(), FunctionCall2Coll(), GBUF_LEAF, GBUF_NULLS, spgChooseIn::hasPrefix, index_getprocid(), index_getprocinfo(), InvalidBlockNumber, InvalidBuffer, InvalidOffsetNumber, spgChooseIn::leafDatum, spgChooseIn::level, LockBuffer(), spgConfigOut::longValuesOK, spgChooseOut::matchNode, Min, moveLeafs(), spgChooseIn::nNodes, SpGistInnerTupleData::nNodes, SPPageDesc::node, spgChooseIn::nodeLabels, SPPageDesc::offnum, OidIsValid, SPPageDesc::page, PageGetItem, PageGetItemId, pfree(), PG_DETOAST_DATUM, PointerGetDatum, spgChooseIn::prefixDatum, SpGistInnerTupleData::prefixSize, random(), RelationData::rd_indcollation, ReadBuffer(), RelationGetRelationName, ReleaseBuffer(), spgChooseOut::result, spgChooseOut::resultType, SGDTSIZE, SGITDATUM, SGLTHDRSZ, SpGistLeafTupleData::size, spgAddNode, spgAddNodeAction(), spgExtractNodeLabels(), spgFormLeafTuple(), SPGIST_CHOOSE_PROC, SPGIST_COMPRESS_PROC, SPGIST_NULL_BLKNO, SPGIST_PAGE_CAPACITY, SPGIST_ROOT_BLKNO, SpGistGetBuffer(), SpGistGetTypeSize(), SpGistPageGetFreeSpace, SpGistPageIsLeaf, SpGistPageStoresNulls, SpGistSetLastUsedPage(), spgMatchNode, spgMatchNodeAction(), spgSplitNodeAction(), spgSplitTuple, SpGistTypeDesc::type, and UnlockReleaseBuffer().

Referenced by spginsert(), and spgistBuildCallback().

1893 {
1894  int level = 0;
1895  Datum leafDatum;
1896  int leafSize;
1897  SPPageDesc current,
1898  parent;
1899  FmgrInfo *procinfo = NULL;
1900 
1901  /*
1902  * Look up FmgrInfo of the user-defined choose function once, to save
1903  * cycles in the loop below.
1904  */
1905  if (!isnull)
1906  procinfo = index_getprocinfo(index, 1, SPGIST_CHOOSE_PROC);
1907 
1908  /*
1909  * Prepare the leaf datum to insert.
1910  *
1911  * If an optional "compress" method is provided, then call it to form the
1912  * leaf datum from the input datum. Otherwise store the input datum as
1913  * is. Since we don't use index_form_tuple in this AM, we have to make
1914  * sure value to be inserted is not toasted; FormIndexDatum doesn't
1915  * guarantee that. But we assume the "compress" method to return an
1916  * untoasted value.
1917  */
1918  if (!isnull)
1919  {
1921  {
1922  FmgrInfo *compressProcinfo = NULL;
1923 
1924  compressProcinfo = index_getprocinfo(index, 1, SPGIST_COMPRESS_PROC);
1925  leafDatum = FunctionCall1Coll(compressProcinfo,
1926  index->rd_indcollation[0],
1927  datum);
1928  }
1929  else
1930  {
1931  Assert(state->attLeafType.type == state->attType.type);
1932 
1933  if (state->attType.attlen == -1)
1934  leafDatum = PointerGetDatum(PG_DETOAST_DATUM(datum));
1935  else
1936  leafDatum = datum;
1937  }
1938  }
1939  else
1940  leafDatum = (Datum) 0;
1941 
1942  /*
1943  * Compute space needed for a leaf tuple containing the given datum.
1944  *
1945  * If it isn't gonna fit, and the opclass can't reduce the datum size by
1946  * suffixing, bail out now rather than getting into an endless loop.
1947  */
1948  if (!isnull)
1949  leafSize = SGLTHDRSZ + sizeof(ItemIdData) +
1950  SpGistGetTypeSize(&state->attLeafType, leafDatum);
1951  else
1952  leafSize = SGDTSIZE + sizeof(ItemIdData);
1953 
1954  if (leafSize > SPGIST_PAGE_CAPACITY && !state->config.longValuesOK)
1955  ereport(ERROR,
1956  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
1957  errmsg("index row size %zu exceeds maximum %zu for index \"%s\"",
1958  leafSize - sizeof(ItemIdData),
1959  SPGIST_PAGE_CAPACITY - sizeof(ItemIdData),
1960  RelationGetRelationName(index)),
1961  errhint("Values larger than a buffer page cannot be indexed.")));
1962 
1963  /* Initialize "current" to the appropriate root page */
1964  current.blkno = isnull ? SPGIST_NULL_BLKNO : SPGIST_ROOT_BLKNO;
1965  current.buffer = InvalidBuffer;
1966  current.page = NULL;
1967  current.offnum = FirstOffsetNumber;
1968  current.node = -1;
1969 
1970  /* "parent" is invalid for the moment */
1971  parent.blkno = InvalidBlockNumber;
1972  parent.buffer = InvalidBuffer;
1973  parent.page = NULL;
1974  parent.offnum = InvalidOffsetNumber;
1975  parent.node = -1;
1976 
1977  for (;;)
1978  {
1979  bool isNew = false;
1980 
1981  /*
1982  * Bail out if query cancel is pending. We must have this somewhere
1983  * in the loop since a broken opclass could produce an infinite
1984  * picksplit loop.
1985  */
1987 
1988  if (current.blkno == InvalidBlockNumber)
1989  {
1990  /*
1991  * Create a leaf page. If leafSize is too large to fit on a page,
1992  * we won't actually use the page yet, but it simplifies the API
1993  * for doPickSplit to always have a leaf page at hand; so just
1994  * quietly limit our request to a page size.
1995  */
1996  current.buffer =
1997  SpGistGetBuffer(index,
1998  GBUF_LEAF | (isnull ? GBUF_NULLS : 0),
1999  Min(leafSize, SPGIST_PAGE_CAPACITY),
2000  &isNew);
2001  current.blkno = BufferGetBlockNumber(current.buffer);
2002  }
2003  else if (parent.buffer == InvalidBuffer)
2004  {
2005  /* we hold no parent-page lock, so no deadlock is possible */
2006  current.buffer = ReadBuffer(index, current.blkno);
2008  }
2009  else if (current.blkno != parent.blkno)
2010  {
2011  /* descend to a new child page */
2012  current.buffer = ReadBuffer(index, current.blkno);
2013 
2014  /*
2015  * Attempt to acquire lock on child page. We must beware of
2016  * deadlock against another insertion process descending from that
2017  * page to our parent page (see README). If we fail to get lock,
2018  * abandon the insertion and tell our caller to start over.
2019  *
2020  * XXX this could be improved, because failing to get lock on a
2021  * buffer is not proof of a deadlock situation; the lock might be
2022  * held by a reader, or even just background writer/checkpointer
2023  * process. Perhaps it'd be worth retrying after sleeping a bit?
2024  */
2025  if (!ConditionalLockBuffer(current.buffer))
2026  {
2027  ReleaseBuffer(current.buffer);
2028  UnlockReleaseBuffer(parent.buffer);
2029  return false;
2030  }
2031  }
2032  else
2033  {
2034  /* inner tuple can be stored on the same page as parent one */
2035  current.buffer = parent.buffer;
2036  }
2037  current.page = BufferGetPage(current.buffer);
2038 
2039  /* should not arrive at a page of the wrong type */
2040  if (isnull ? !SpGistPageStoresNulls(current.page) :
2041  SpGistPageStoresNulls(current.page))
2042  elog(ERROR, "SPGiST index page %u has wrong nulls flag",
2043  current.blkno);
2044 
2045  if (SpGistPageIsLeaf(current.page))
2046  {
2047  SpGistLeafTuple leafTuple;
2048  int nToSplit,
2049  sizeToSplit;
2050 
2051  leafTuple = spgFormLeafTuple(state, heapPtr, leafDatum, isnull);
2052  if (leafTuple->size + sizeof(ItemIdData) <=
2053  SpGistPageGetFreeSpace(current.page, 1))
2054  {
2055  /* it fits on page, so insert it and we're done */
2056  addLeafTuple(index, state, leafTuple,
2057  &current, &parent, isnull, isNew);
2058  break;
2059  }
2060  else if ((sizeToSplit =
2061  checkSplitConditions(index, state, &current,
2062  &nToSplit)) < SPGIST_PAGE_CAPACITY / 2 &&
2063  nToSplit < 64 &&
2064  leafTuple->size + sizeof(ItemIdData) + sizeToSplit <= SPGIST_PAGE_CAPACITY)
2065  {
2066  /*
2067  * the amount of data is pretty small, so just move the whole
2068  * chain to another leaf page rather than splitting it.
2069  */
2070  Assert(!isNew);
2071  moveLeafs(index, state, &current, &parent, leafTuple, isnull);
2072  break; /* we're done */
2073  }
2074  else
2075  {
2076  /* picksplit */
2077  if (doPickSplit(index, state, &current, &parent,
2078  leafTuple, level, isnull, isNew))
2079  break; /* doPickSplit installed new tuples */
2080 
2081  /* leaf tuple will not be inserted yet */
2082  pfree(leafTuple);
2083 
2084  /*
2085  * current now describes new inner tuple, go insert into it
2086  */
2087  Assert(!SpGistPageIsLeaf(current.page));
2088  goto process_inner_tuple;
2089  }
2090  }
2091  else /* non-leaf page */
2092  {
2093  /*
2094  * Apply the opclass choose function to figure out how to insert
2095  * the given datum into the current inner tuple.
2096  */
2097  SpGistInnerTuple innerTuple;
2098  spgChooseIn in;
2099  spgChooseOut out;
2100 
2101  /*
2102  * spgAddNode and spgSplitTuple cases will loop back to here to
2103  * complete the insertion operation. Just in case the choose
2104  * function is broken and produces add or split requests
2105  * repeatedly, check for query cancel.
2106  */
2107  process_inner_tuple:
2109 
2110  innerTuple = (SpGistInnerTuple) PageGetItem(current.page,
2111  PageGetItemId(current.page, current.offnum));
2112 
2113  in.datum = datum;
2114  in.leafDatum = leafDatum;
2115  in.level = level;
2116  in.allTheSame = innerTuple->allTheSame;
2117  in.hasPrefix = (innerTuple->prefixSize > 0);
2118  in.prefixDatum = SGITDATUM(innerTuple, state);
2119  in.nNodes = innerTuple->nNodes;
2120  in.nodeLabels = spgExtractNodeLabels(state, innerTuple);
2121 
2122  memset(&out, 0, sizeof(out));
2123 
2124  if (!isnull)
2125  {
2126  /* use user-defined choose method */
2127  FunctionCall2Coll(procinfo,
2128  index->rd_indcollation[0],
2129  PointerGetDatum(&in),
2130  PointerGetDatum(&out));
2131  }
2132  else
2133  {
2134  /* force "match" action (to insert to random subnode) */
2135  out.resultType = spgMatchNode;
2136  }
2137 
2138  if (innerTuple->allTheSame)
2139  {
2140  /*
2141  * It's not allowed to do an AddNode at an allTheSame tuple.
2142  * Opclass must say "match", in which case we choose a random
2143  * one of the nodes to descend into, or "split".
2144  */
2145  if (out.resultType == spgAddNode)
2146  elog(ERROR, "cannot add a node to an allTheSame inner tuple");
2147  else if (out.resultType == spgMatchNode)
2148  out.result.matchNode.nodeN = random() % innerTuple->nNodes;
2149  }
2150 
2151  switch (out.resultType)
2152  {
2153  case spgMatchNode:
2154  /* Descend to N'th child node */
2155  spgMatchNodeAction(index, state, innerTuple,
2156  &current, &parent,
2157  out.result.matchNode.nodeN);
2158  /* Adjust level as per opclass request */
2159  level += out.result.matchNode.levelAdd;
2160  /* Replace leafDatum and recompute leafSize */
2161  if (!isnull)
2162  {
2163  leafDatum = out.result.matchNode.restDatum;
2164  leafSize = SGLTHDRSZ + sizeof(ItemIdData) +
2165  SpGistGetTypeSize(&state->attLeafType, leafDatum);
2166  }
2167 
2168  /*
2169  * Loop around and attempt to insert the new leafDatum at
2170  * "current" (which might reference an existing child
2171  * tuple, or might be invalid to force us to find a new
2172  * page for the tuple).
2173  *
2174  * Note: if the opclass sets longValuesOK, we rely on the
2175  * choose function to eventually shorten the leafDatum
2176  * enough to fit on a page. We could add a test here to
2177  * complain if the datum doesn't get visibly shorter each
2178  * time, but that could get in the way of opclasses that
2179  * "simplify" datums in a way that doesn't necessarily
2180  * lead to physical shortening on every cycle.
2181  */
2182  break;
2183  case spgAddNode:
2184  /* AddNode is not sensible if nodes don't have labels */
2185  if (in.nodeLabels == NULL)
2186  elog(ERROR, "cannot add a node to an inner tuple without node labels");
2187  /* Add node to inner tuple, per request */
2188  spgAddNodeAction(index, state, innerTuple,
2189  &current, &parent,
2190  out.result.addNode.nodeN,
2191  out.result.addNode.nodeLabel);
2192 
2193  /*
2194  * Retry insertion into the enlarged node. We assume that
2195  * we'll get a MatchNode result this time.
2196  */
2197  goto process_inner_tuple;
2198  break;
2199  case spgSplitTuple:
2200  /* Split inner tuple, per request */
2201  spgSplitNodeAction(index, state, innerTuple,
2202  &current, &out);
2203 
2204  /* Retry insertion into the split node */
2205  goto process_inner_tuple;
2206  break;
2207  default:
2208  elog(ERROR, "unrecognized SPGiST choose result: %d",
2209  (int) out.resultType);
2210  break;
2211  }
2212  }
2213  } /* end loop */
2214 
2215  /*
2216  * Release any buffers we're still holding. Beware of possibility that
2217  * current and parent reference same buffer.
2218  */
2219  if (current.buffer != InvalidBuffer)
2220  {
2221  SpGistSetLastUsedPage(index, current.buffer);
2222  UnlockReleaseBuffer(current.buffer);
2223  }
2224  if (parent.buffer != InvalidBuffer &&
2225  parent.buffer != current.buffer)
2226  {
2227  SpGistSetLastUsedPage(index, parent.buffer);
2228  UnlockReleaseBuffer(parent.buffer);
2229  }
2230 
2231  return true;
2232 }
Definition: fmgr.h:56
Datum * spgExtractNodeLabels(SpGistState *state, SpGistInnerTuple innerTuple)
Definition: spgutils.c:822
Datum datum
Definition: spgist.h:59
SpGistInnerTupleData * SpGistInnerTuple
#define SpGistPageIsLeaf(page)
bool hasPrefix
Definition: spgist.h:65
int errhint(const char *fmt,...)
Definition: elog.c:987
#define SpGistPageGetFreeSpace(p, n)
FmgrInfo * index_getprocinfo(Relation irel, AttrNumber attnum, uint16 procnum)
Definition: indexam.c:855
#define SGDTSIZE
int level
Definition: spgist.h:61
struct spgChooseOut::@48::@49 matchNode
#define PointerGetDatum(X)
Definition: postgres.h:541
long random(void)
Definition: random.c:22
SpGistTypeDesc attLeafType
#define Min(x, y)
Definition: c.h:857
SpGistTypeDesc attType
void SpGistSetLastUsedPage(Relation index, Buffer buffer)
Definition: spgutils.c:494
#define InvalidBuffer
Definition: buf.h:25
Datum prefixDatum
Definition: spgist.h:66
int errcode(int sqlerrcode)
Definition: elog.c:575
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3309
#define BUFFER_LOCK_EXCLUSIVE
Definition: bufmgr.h:89
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1133
#define SPGIST_ROOT_BLKNO
#define OidIsValid(objectId)
Definition: c.h:605
#define SGITDATUM(x, s)
static void addLeafTuple(Relation index, SpGistState *state, SpGistLeafTuple leafTuple, SPPageDesc *current, SPPageDesc *parent, bool isNulls, bool isNew)
Definition: spgdoinsert.c:203
spgConfigOut config
void pfree(void *pointer)
Definition: mcxt.c:1031
unsigned int allTheSame
static bool doPickSplit(Relation index, SpGistState *state, SPPageDesc *current, SPPageDesc *parent, SpGistLeafTuple newLeafTuple, int level, bool isNulls, bool isNew)
Definition: spgdoinsert.c:675
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3332
Oid * rd_indcollation
Definition: rel.h:165
#define ERROR
Definition: elog.h:43
unsigned int prefixSize
#define SPGIST_NULL_BLKNO
#define FirstOffsetNumber
Definition: off.h:27
OffsetNumber offnum
Definition: spgdoinsert.c:39
static void spgSplitNodeAction(Relation index, SpGistState *state, SpGistInnerTuple innerTuple, SPPageDesc *current, spgChooseOut *out)
Definition: spgdoinsert.c:1692
#define RelationGetRelationName(relation)
Definition: rel.h:441
struct ItemIdData ItemIdData
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
#define ereport(elevel, rest)
Definition: elog.h:122
bool ConditionalLockBuffer(Buffer buffer)
Definition: bufmgr.c:3572
int nNodes
Definition: spgist.h:67
#define SGLTHDRSZ
#define GBUF_LEAF
unsigned int SpGistGetTypeSize(SpGistTypeDesc *att, Datum datum)
Definition: spgutils.c:593
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:231
SpGistLeafTuple spgFormLeafTuple(SpGistState *state, ItemPointer heapPtr, Datum datum, bool isnull)
Definition: spgutils.c:630
bool longValuesOK
Definition: spgist.h:51
uintptr_t Datum
Definition: postgres.h:367
Datum FunctionCall1Coll(FmgrInfo *flinfo, Oid collation, Datum arg1)
Definition: fmgr.c:1113
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3546
#define SPGIST_PAGE_CAPACITY
spgChooseResultType resultType
Definition: spgist.h:80
#define InvalidOffsetNumber
Definition: off.h:26
#define SpGistPageStoresNulls(page)
static void spgMatchNodeAction(Relation index, SpGistState *state, SpGistInnerTuple innerTuple, SPPageDesc *current, SPPageDesc *parent, int nodeN)
Definition: spgdoinsert.c:1436
#define Assert(condition)
Definition: c.h:699
Datum leafDatum
Definition: spgist.h:60
struct spgChooseOut::@48::@50 addNode
Buffer SpGistGetBuffer(Relation index, int flags, int needSpace, bool *isNew)
Definition: spgutils.c:389
#define SPGIST_COMPRESS_PROC
Definition: spgist.h:33
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:594
#define InvalidBlockNumber
Definition: block.h:33
#define GBUF_NULLS
union spgChooseOut::@48 result
static void spgAddNodeAction(Relation index, SpGistState *state, SpGistInnerTuple innerTuple, SPPageDesc *current, SPPageDesc *parent, int nodeN, Datum nodeLabel)
Definition: spgdoinsert.c:1490
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2605
Datum * nodeLabels
Definition: spgist.h:68
int errmsg(const char *fmt,...)
Definition: elog.c:797
bool allTheSame
Definition: spgist.h:64
static int checkSplitConditions(Relation index, SpGistState *state, SPPageDesc *current, int *nToSplit)
Definition: spgdoinsert.c:333
Buffer buffer
Definition: spgdoinsert.c:37
#define PG_DETOAST_DATUM(datum)
Definition: fmgr.h:210
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:98
#define elog
Definition: elog.h:219
#define SPGIST_CHOOSE_PROC
Definition: spgist.h:29
static void moveLeafs(Relation index, SpGistState *state, SPPageDesc *current, SPPageDesc *parent, SpGistLeafTuple newLeafTuple, bool isNulls)
Definition: spgdoinsert.c:387
#define PageGetItem(page, itemId)
Definition: bufpage.h:336
BlockNumber blkno
Definition: spgdoinsert.c:36
RegProcedure index_getprocid(Relation irel, AttrNumber attnum, uint16 procnum)
Definition: indexam.c:821

◆ spgExtractNodeLabels()

Datum* spgExtractNodeLabels ( SpGistState state,
SpGistInnerTuple  innerTuple 
)

Definition at line 822 of file spgutils.c.

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

Referenced by spgdoinsert(), and spgWalk().

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

◆ spgFormDeadTuple()

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

Definition at line 792 of file spgutils.c.

References Assert, SpGistState::deadTupleStorage, InvalidOffsetNumber, InvalidTransactionId, ItemPointerSet, ItemPointerSetInvalid, SpGistState::myXid, SpGistDeadTupleData::nextOffset, SpGistDeadTupleData::pointer, SGDTSIZE, SpGistDeadTupleData::size, SPGIST_REDIRECT, TransactionIdIsValid, SpGistDeadTupleData::tupstate, and SpGistDeadTupleData::xid.

Referenced by spgAddNodeAction(), spgPageIndexMultiDelete(), and spgRedoAddNode().

794 {
796 
797  tuple->tupstate = tupstate;
798  tuple->size = SGDTSIZE;
800 
801  if (tupstate == SPGIST_REDIRECT)
802  {
803  ItemPointerSet(&tuple->pointer, blkno, offnum);
805  tuple->xid = state->myXid;
806  }
807  else
808  {
810  tuple->xid = InvalidTransactionId;
811  }
812 
813  return tuple;
814 }
#define SGDTSIZE
#define SPGIST_REDIRECT
ItemPointerData pointer
SpGistDeadTupleData * SpGistDeadTuple
#define InvalidTransactionId
Definition: transam.h:31
TransactionId myXid
unsigned int tupstate
char * deadTupleStorage
OffsetNumber nextOffset
#define InvalidOffsetNumber
Definition: off.h:26
#define Assert(condition)
Definition: c.h:699
#define ItemPointerSetInvalid(pointer)
Definition: itemptr.h:172
#define TransactionIdIsValid(xid)
Definition: transam.h:41
#define ItemPointerSet(pointer, blockNumber, offNum)
Definition: itemptr.h:127

◆ spgFormInnerTuple()

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

Definition at line 709 of file spgutils.c.

References SpGistState::attPrefixType, elog, ereport, errcode(), errhint(), errmsg(), ERROR, i, IndexTupleSize, memcpyDatum(), SpGistInnerTupleData::nNodes, palloc0(), SpGistInnerTupleData::prefixSize, SGDTSIZE, SGITDATAPTR, SGITHDRSZ, SGITMAXNNODES, SGITMAXPREFIXSIZE, SGITMAXSIZE, SGITNODEPTR, SpGistInnerTupleData::size, SPGIST_PAGE_CAPACITY, and SpGistGetTypeSize().

Referenced by addNode(), doPickSplit(), and spgSplitNodeAction().

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

◆ spgFormLeafTuple()

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

Definition at line 630 of file spgutils.c.

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

Referenced by doPickSplit(), and spgdoinsert().

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

◆ spgFormNodeTuple()

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

Definition at line 667 of file spgutils.c.

References SpGistState::attLabelType, ereport, errcode(), errmsg(), ERROR, INDEX_NULL_MASK, INDEX_SIZE_MASK, ItemPointerSetInvalid, memcpyDatum(), palloc0(), SGNTDATAPTR, SGNTHDRSZ, SpGistGetTypeSize(), IndexTupleData::t_info, and IndexTupleData::t_tid.

Referenced by addNode(), doPickSplit(), and spgSplitNodeAction().

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

◆ spgGetCache()

SpGistCache* spgGetCache ( Relation  index)

Definition at line 93 of file spgutils.c.

References Assert, SpGistCache::attLabelType, SpGistCache::attLeafType, SpGistCache::attPrefixType, spgConfigIn::attType, SpGistCache::attType, BUFFER_LOCK_SHARE, BufferGetPage, SpGistCache::config, elog, ereport, errcode(), errmsg(), ERROR, fillTypeDesc(), FunctionCall2Coll(), index_getprocid(), index_getprocinfo(), spgConfigOut::labelType, SpGistMetaPageData::lastUsedPages, SpGistCache::lastUsedPages, spgConfigOut::leafType, LockBuffer(), SpGistMetaPageData::magicNumber, MemoryContextAllocZero(), tupleDesc::natts, OidIsValid, PointerGetDatum, spgConfigOut::prefixType, RelationData::rd_amcache, RelationData::rd_att, RelationData::rd_indcollation, RelationData::rd_indexcxt, ReadBuffer(), RelationGetRelationName, SPGIST_COMPRESS_PROC, SPGIST_CONFIG_PROC, SPGIST_MAGIC_NUMBER, SPGIST_METAPAGE_BLKNO, SpGistPageGetMeta, TupleDescAttr, and UnlockReleaseBuffer().

Referenced by allocNewBuffer(), initSpGistState(), spgcanreturn(), SpGistGetBuffer(), and SpGistSetLastUsedPage().

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

◆ SpGistGetBuffer()

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

Definition at line 389 of file spgutils.c.

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

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

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

◆ SpGistGetTypeSize()

unsigned int SpGistGetTypeSize ( SpGistTypeDesc att,
Datum  datum 
)

Definition at line 593 of file spgutils.c.

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

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

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

◆ SpGistInitBuffer()

void SpGistInitBuffer ( Buffer  b,
uint16  f 
)

Definition at line 544 of file spgutils.c.

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

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

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

◆ SpGistInitMetapage()

void SpGistInitMetapage ( Page  page)

Definition at line 554 of file spgutils.c.

References SpGistLastUsedPage::blkno, SpGistLUPCache::cachedPage, i, InvalidBlockNumber, SpGistMetaPageData::lastUsedPages, SpGistMetaPageData::magicNumber, SPGIST_CACHED_PAGES, SPGIST_MAGIC_NUMBER, SPGIST_META, SpGistInitPage(), and SpGistPageGetMeta.

Referenced by spgbuild(), spgbuildempty(), and spgRedoCreateIndex().

555 {
556  SpGistMetaPageData *metadata;
557  int i;
558 
560  metadata = SpGistPageGetMeta(page);
561  memset(metadata, 0, sizeof(SpGistMetaPageData));
562  metadata->magicNumber = SPGIST_MAGIC_NUMBER;
563 
564  /* initialize last-used-page cache to empty */
565  for (i = 0; i < SPGIST_CACHED_PAGES; i++)
567 
568  /*
569  * Set pd_lower just past the end of the metadata. This is essential,
570  * because without doing so, metadata will be lost if xlog.c compresses
571  * the page.
572  */
573  ((PageHeader) page)->pd_lower =
574  ((char *) metadata + sizeof(SpGistMetaPageData)) - (char *) page;
575 }
SpGistLastUsedPage cachedPage[SPGIST_CACHED_PAGES]
#define SPGIST_META
#define SPGIST_MAGIC_NUMBER
SpGistLUPCache lastUsedPages
#define InvalidBlockNumber
Definition: block.h:33
#define SPGIST_CACHED_PAGES
#define SpGistPageGetMeta(p)
void SpGistInitPage(Page page, uint16 f)
Definition: spgutils.c:529
int i

◆ SpGistInitPage()

void SpGistInitPage ( Page  page,
uint16  f 
)

Definition at line 529 of file spgutils.c.

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

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

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

◆ SpGistNewBuffer()

Buffer SpGistNewBuffer ( Relation  index)

Definition at line 205 of file spgutils.c.

References buffer, BUFFER_LOCK_EXCLUSIVE, BUFFER_LOCK_UNLOCK, BufferGetPage, ConditionalLockBuffer(), ExclusiveLock, GetFreeIndexPage(), InvalidBlockNumber, LockBuffer(), LockRelationForExtension(), P_NEW, PageIsEmpty, PageIsNew, ReadBuffer(), RELATION_IS_LOCAL, ReleaseBuffer(), SpGistBlockIsFixed, SpGistPageIsDeleted, and UnlockRelationForExtension().

Referenced by allocNewBuffer(), and spgbuild().

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

◆ SpGistPageAddNewItem()

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

Definition at line 865 of file spgutils.c.

References Assert, elog, ERROR, FirstOffsetNumber, i, InvalidOffsetNumber, MAXALIGN, SpGistPageOpaqueData::nPlaceholder, PageAddItem, PageGetExactFreeSpace(), PageGetItem, PageGetItemId, PageGetMaxOffsetNumber, PageIndexTupleDelete(), PANIC, SGDTSIZE, SPGIST_PLACEHOLDER, SpGistPageGetOpaque, and SpGistDeadTupleData::tupstate.

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

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

◆ SpGistSetLastUsedPage()

void SpGistSetLastUsedPage ( Relation  index,
Buffer  buffer 
)

Definition at line 494 of file spgutils.c.

References SpGistLastUsedPage::blkno, BufferGetBlockNumber(), BufferGetPage, SpGistLastUsedPage::freeSpace, GBUF_INNER_PARITY, GBUF_LEAF, GBUF_NULLS, GET_LUP, InvalidBlockNumber, PageGetExactFreeSpace(), spgGetCache(), SpGistBlockIsFixed, SpGistPageIsLeaf, and SpGistPageStoresNulls.

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

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

◆ SpGistUpdateMetaPage()

void SpGistUpdateMetaPage ( Relation  index)

Definition at line 270 of file spgutils.c.

References BufferGetPage, ConditionalLockBuffer(), SpGistMetaPageData::lastUsedPages, SpGistCache::lastUsedPages, MarkBufferDirty(), RelationData::rd_amcache, ReadBuffer(), ReleaseBuffer(), SPGIST_METAPAGE_BLKNO, SpGistPageGetMeta, and UnlockReleaseBuffer().

Referenced by spgbuild(), spginsert(), and spgvacuumscan().

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

◆ spgPageIndexMultiDelete()

void spgPageIndexMultiDelete ( SpGistState state,
Page  page,
OffsetNumber itemnos,
int  nitems,
int  firststate,
int  reststate,
BlockNumber  blkno,
OffsetNumber  offnum 
)

Definition at line 131 of file spgdoinsert.c.

References cmpOffsetNumbers(), elog, ERROR, i, MaxIndexTuplesPerPage, PageAddItem, PageIndexMultiDelete(), qsort, SpGistDeadTupleData::size, spgFormDeadTuple(), SPGIST_PLACEHOLDER, SPGIST_REDIRECT, SpGistPageGetOpaque, and SpGistDeadTupleData::tupstate.

Referenced by doPickSplit(), moveLeafs(), spgRedoMoveLeafs(), spgRedoPickSplit(), spgRedoVacuumLeaf(), and vacuumLeafPage().

135 {
136  OffsetNumber firstItem;
138  SpGistDeadTuple tuple = NULL;
139  int i;
140 
141  if (nitems == 0)
142  return; /* nothing to do */
143 
144  /*
145  * For efficiency we want to use PageIndexMultiDelete, which requires the
146  * targets to be listed in sorted order, so we have to sort the itemnos
147  * array. (This also greatly simplifies the math for reinserting the
148  * replacement tuples.) However, we must not scribble on the caller's
149  * array, so we have to make a copy.
150  */
151  memcpy(sortednos, itemnos, sizeof(OffsetNumber) * nitems);
152  if (nitems > 1)
153  qsort(sortednos, nitems, sizeof(OffsetNumber), cmpOffsetNumbers);
154 
155  PageIndexMultiDelete(page, sortednos, nitems);
156 
157  firstItem = itemnos[0];
158 
159  for (i = 0; i < nitems; i++)
160  {
161  OffsetNumber itemno = sortednos[i];
162  int tupstate;
163 
164  tupstate = (itemno == firstItem) ? firststate : reststate;
165  if (tuple == NULL || tuple->tupstate != tupstate)
166  tuple = spgFormDeadTuple(state, tupstate, blkno, offnum);
167 
168  if (PageAddItem(page, (Item) tuple, tuple->size,
169  itemno, false, false) != itemno)
170  elog(ERROR, "failed to add item of size %u to SPGiST index page",
171  tuple->size);
172 
173  if (tupstate == SPGIST_REDIRECT)
174  SpGistPageGetOpaque(page)->nRedirection++;
175  else if (tupstate == SPGIST_PLACEHOLDER)
176  SpGistPageGetOpaque(page)->nPlaceholder++;
177  }
178 }
SpGistDeadTuple spgFormDeadTuple(SpGistState *state, int tupstate, BlockNumber blkno, OffsetNumber offnum)
Definition: spgutils.c:792
#define SPGIST_REDIRECT
#define SPGIST_PLACEHOLDER
Pointer Item
Definition: item.h:17
#define PageAddItem(page, item, size, offsetNumber, overwrite, is_heap)
Definition: bufpage.h:412
uint16 OffsetNumber
Definition: off.h:24
#define ERROR
Definition: elog.h:43
unsigned int tupstate
void PageIndexMultiDelete(Page page, OffsetNumber *itemnos, int nitems)
Definition: bufpage.c:832
#define SpGistPageGetOpaque(page)
#define MaxIndexTuplesPerPage
Definition: itup.h:145
int i
#define elog
Definition: elog.h:219
#define qsort(a, b, c, d)
Definition: port.h:421
static int cmpOffsetNumbers(const void *a, const void *b)
Definition: spgdoinsert.c:110

◆ spgUpdateNodeLink()

void spgUpdateNodeLink ( SpGistInnerTuple  tup,
int  nodeN,
BlockNumber  blkno,
OffsetNumber  offset 
)

Definition at line 50 of file spgdoinsert.c.

References elog, ERROR, i, ItemPointerSet, SPPageDesc::node, SGITITERATE, and IndexTupleData::t_tid.

Referenced by saveNodeLink(), spgRedoAddLeaf(), spgRedoAddNode(), spgRedoMoveLeafs(), spgRedoPickSplit(), and spgSplitNodeAction().

52 {
53  int i;
54  SpGistNodeTuple node;
55 
56  SGITITERATE(tup, i, node)
57  {
58  if (i == nodeN)
59  {
60  ItemPointerSet(&node->t_tid, blkno, offset);
61  return;
62  }
63  }
64 
65  elog(ERROR, "failed to find requested node %d in SPGiST inner tuple",
66  nodeN);
67 }
#define SGITITERATE(x, i, nt)
ItemPointerData t_tid
Definition: itup.h:37
#define ERROR
Definition: elog.h:43
int i
#define elog
Definition: elog.h:219
#define ItemPointerSet(pointer, blockNumber, offNum)
Definition: itemptr.h:127