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 229 of file spgist_private.h.

◆ GBUF_INNER_PARITY

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

◆ GBUF_LEAF

#define GBUF_LEAF   0x03

Definition at line 374 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 378 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 379 of file spgist_private.h.

Referenced by allocNewBuffer(), and SpGistGetBuffer().

◆ GBUF_REQ_NULLS

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

Definition at line 380 of file spgist_private.h.

Referenced by allocNewBuffer(), and SpGistGetBuffer().

◆ SGDTSIZE

◆ SGITDATAPTR

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

Definition at line 230 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:372

Definition at line 231 of file spgist_private.h.

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

◆ SGITHDRSZ

#define SGITHDRSZ   MAXALIGN(sizeof(SpGistInnerTupleData))

Definition at line 228 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:70
SpGistNodeTupleData * SpGistNodeTuple

Definition at line 239 of file spgist_private.h.

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

◆ SGITMAXNNODES

#define SGITMAXNNODES   0x1FFF

Definition at line 224 of file spgist_private.h.

Referenced by spgFormInnerTuple(), and spgSplitNodeAction().

◆ SGITMAXPREFIXSIZE

#define SGITMAXPREFIXSIZE   0xFFFF

Definition at line 225 of file spgist_private.h.

Referenced by spgFormInnerTuple().

◆ SGITMAXSIZE

#define SGITMAXSIZE   0xFFFF

Definition at line 226 of file spgist_private.h.

Referenced by spgFormInnerTuple().

◆ SGITNODEPTR

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

Definition at line 236 of file spgist_private.h.

Referenced by spgExtractNodeLabels(), and spgFormInnerTuple().

◆ SGLTDATAPTR

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

Definition at line 302 of file spgist_private.h.

Referenced by spgFormLeafTuple().

◆ SGLTDATUM

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

Definition at line 303 of file spgist_private.h.

Referenced by doPickSplit(), and spgLeafTest().

◆ SGLTHDRSZ

#define SGLTHDRSZ   MAXALIGN(sizeof(SpGistLeafTupleData))

Definition at line 301 of file spgist_private.h.

Referenced by spgdoinsert(), and spgFormLeafTuple().

◆ SGNTDATAPTR

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

Definition at line 259 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:562
uintptr_t Datum
Definition: postgres.h:372
#define SGNTDATAPTR(x)

Definition at line 260 of file spgist_private.h.

Referenced by spgExtractNodeLabels().

◆ SGNTHDRSZ

#define SGNTHDRSZ   MAXALIGN(sizeof(SpGistNodeTupleData))

Definition at line 258 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:633
#define MAXALIGN_DOWN(LEN)
Definition: c.h:645

Definition at line 339 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 348 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 357 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 158 of file spgutils.c.

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

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

159 {
160  SpGistCache *cache;
161 
162  /* Get cached static information about index */
163  cache = spgGetCache(index);
164 
165  state->config = cache->config;
166  state->attType = cache->attType;
167  state->attPrefixType = cache->attPrefixType;
168  state->attLabelType = cache->attLabelType;
169 
170  /* Make workspace for constructing dead tuples */
172 
173  /* Set XID to use in redirection tuples */
174  state->myXid = GetTopTransactionIdIfAny();
175 
176  /* Assume we're not in an index build (spgbuild will override) */
177  state->isBuild = false;
178 }
SpGistTypeDesc attPrefixType
SpGistCache * spgGetCache(Relation index)
Definition: spgutils.c:92
#define SGDTSIZE
SpGistTypeDesc attType
SpGistTypeDesc attLabelType
SpGistTypeDesc attType
spgConfigOut config
TransactionId myXid
TransactionId GetTopTransactionIdIfAny(void)
Definition: xact.c:405
spgConfigOut config
void * palloc0(Size size)
Definition: mcxt.c:864
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, 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, FunctionCall2Coll(), GBUF_LEAF, GBUF_NULLS, spgChooseIn::hasPrefix, 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, 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_NULL_BLKNO, SPGIST_PAGE_CAPACITY, SPGIST_ROOT_BLKNO, SpGistGetBuffer(), SpGistGetTypeSize(), SpGistPageGetFreeSpace, SpGistPageIsLeaf, SpGistPageStoresNulls, SpGistSetLastUsedPage(), spgMatchNode, spgMatchNodeAction(), spgSplitNodeAction(), spgSplitTuple, 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  * Since we don't use index_form_tuple in this AM, we have to make sure
1910  * value to be inserted is not toasted; FormIndexDatum doesn't guarantee
1911  * that.
1912  */
1913  if (!isnull && state->attType.attlen == -1)
1914  datum = PointerGetDatum(PG_DETOAST_DATUM(datum));
1915 
1916  leafDatum = datum;
1917 
1918  /*
1919  * Compute space needed for a leaf tuple containing the given datum.
1920  *
1921  * If it isn't gonna fit, and the opclass can't reduce the datum size by
1922  * suffixing, bail out now rather than getting into an endless loop.
1923  */
1924  if (!isnull)
1925  leafSize = SGLTHDRSZ + sizeof(ItemIdData) +
1926  SpGistGetTypeSize(&state->attType, leafDatum);
1927  else
1928  leafSize = SGDTSIZE + sizeof(ItemIdData);
1929 
1930  if (leafSize > SPGIST_PAGE_CAPACITY && !state->config.longValuesOK)
1931  ereport(ERROR,
1932  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
1933  errmsg("index row size %zu exceeds maximum %zu for index \"%s\"",
1934  leafSize - sizeof(ItemIdData),
1935  SPGIST_PAGE_CAPACITY - sizeof(ItemIdData),
1936  RelationGetRelationName(index)),
1937  errhint("Values larger than a buffer page cannot be indexed.")));
1938 
1939  /* Initialize "current" to the appropriate root page */
1940  current.blkno = isnull ? SPGIST_NULL_BLKNO : SPGIST_ROOT_BLKNO;
1941  current.buffer = InvalidBuffer;
1942  current.page = NULL;
1943  current.offnum = FirstOffsetNumber;
1944  current.node = -1;
1945 
1946  /* "parent" is invalid for the moment */
1947  parent.blkno = InvalidBlockNumber;
1948  parent.buffer = InvalidBuffer;
1949  parent.page = NULL;
1950  parent.offnum = InvalidOffsetNumber;
1951  parent.node = -1;
1952 
1953  for (;;)
1954  {
1955  bool isNew = false;
1956 
1957  /*
1958  * Bail out if query cancel is pending. We must have this somewhere
1959  * in the loop since a broken opclass could produce an infinite
1960  * picksplit loop.
1961  */
1963 
1964  if (current.blkno == InvalidBlockNumber)
1965  {
1966  /*
1967  * Create a leaf page. If leafSize is too large to fit on a page,
1968  * we won't actually use the page yet, but it simplifies the API
1969  * for doPickSplit to always have a leaf page at hand; so just
1970  * quietly limit our request to a page size.
1971  */
1972  current.buffer =
1973  SpGistGetBuffer(index,
1974  GBUF_LEAF | (isnull ? GBUF_NULLS : 0),
1975  Min(leafSize, SPGIST_PAGE_CAPACITY),
1976  &isNew);
1977  current.blkno = BufferGetBlockNumber(current.buffer);
1978  }
1979  else if (parent.buffer == InvalidBuffer)
1980  {
1981  /* we hold no parent-page lock, so no deadlock is possible */
1982  current.buffer = ReadBuffer(index, current.blkno);
1984  }
1985  else if (current.blkno != parent.blkno)
1986  {
1987  /* descend to a new child page */
1988  current.buffer = ReadBuffer(index, current.blkno);
1989 
1990  /*
1991  * Attempt to acquire lock on child page. We must beware of
1992  * deadlock against another insertion process descending from that
1993  * page to our parent page (see README). If we fail to get lock,
1994  * abandon the insertion and tell our caller to start over.
1995  *
1996  * XXX this could be improved, because failing to get lock on a
1997  * buffer is not proof of a deadlock situation; the lock might be
1998  * held by a reader, or even just background writer/checkpointer
1999  * process. Perhaps it'd be worth retrying after sleeping a bit?
2000  */
2001  if (!ConditionalLockBuffer(current.buffer))
2002  {
2003  ReleaseBuffer(current.buffer);
2004  UnlockReleaseBuffer(parent.buffer);
2005  return false;
2006  }
2007  }
2008  else
2009  {
2010  /* inner tuple can be stored on the same page as parent one */
2011  current.buffer = parent.buffer;
2012  }
2013  current.page = BufferGetPage(current.buffer);
2014 
2015  /* should not arrive at a page of the wrong type */
2016  if (isnull ? !SpGistPageStoresNulls(current.page) :
2017  SpGistPageStoresNulls(current.page))
2018  elog(ERROR, "SPGiST index page %u has wrong nulls flag",
2019  current.blkno);
2020 
2021  if (SpGistPageIsLeaf(current.page))
2022  {
2023  SpGistLeafTuple leafTuple;
2024  int nToSplit,
2025  sizeToSplit;
2026 
2027  leafTuple = spgFormLeafTuple(state, heapPtr, leafDatum, isnull);
2028  if (leafTuple->size + sizeof(ItemIdData) <=
2029  SpGistPageGetFreeSpace(current.page, 1))
2030  {
2031  /* it fits on page, so insert it and we're done */
2032  addLeafTuple(index, state, leafTuple,
2033  &current, &parent, isnull, isNew);
2034  break;
2035  }
2036  else if ((sizeToSplit =
2037  checkSplitConditions(index, state, &current,
2038  &nToSplit)) < SPGIST_PAGE_CAPACITY / 2 &&
2039  nToSplit < 64 &&
2040  leafTuple->size + sizeof(ItemIdData) + sizeToSplit <= SPGIST_PAGE_CAPACITY)
2041  {
2042  /*
2043  * the amount of data is pretty small, so just move the whole
2044  * chain to another leaf page rather than splitting it.
2045  */
2046  Assert(!isNew);
2047  moveLeafs(index, state, &current, &parent, leafTuple, isnull);
2048  break; /* we're done */
2049  }
2050  else
2051  {
2052  /* picksplit */
2053  if (doPickSplit(index, state, &current, &parent,
2054  leafTuple, level, isnull, isNew))
2055  break; /* doPickSplit installed new tuples */
2056 
2057  /* leaf tuple will not be inserted yet */
2058  pfree(leafTuple);
2059 
2060  /*
2061  * current now describes new inner tuple, go insert into it
2062  */
2063  Assert(!SpGistPageIsLeaf(current.page));
2064  goto process_inner_tuple;
2065  }
2066  }
2067  else /* non-leaf page */
2068  {
2069  /*
2070  * Apply the opclass choose function to figure out how to insert
2071  * the given datum into the current inner tuple.
2072  */
2073  SpGistInnerTuple innerTuple;
2074  spgChooseIn in;
2075  spgChooseOut out;
2076 
2077  /*
2078  * spgAddNode and spgSplitTuple cases will loop back to here to
2079  * complete the insertion operation. Just in case the choose
2080  * function is broken and produces add or split requests
2081  * repeatedly, check for query cancel.
2082  */
2083  process_inner_tuple:
2085 
2086  innerTuple = (SpGistInnerTuple) PageGetItem(current.page,
2087  PageGetItemId(current.page, current.offnum));
2088 
2089  in.datum = datum;
2090  in.leafDatum = leafDatum;
2091  in.level = level;
2092  in.allTheSame = innerTuple->allTheSame;
2093  in.hasPrefix = (innerTuple->prefixSize > 0);
2094  in.prefixDatum = SGITDATUM(innerTuple, state);
2095  in.nNodes = innerTuple->nNodes;
2096  in.nodeLabels = spgExtractNodeLabels(state, innerTuple);
2097 
2098  memset(&out, 0, sizeof(out));
2099 
2100  if (!isnull)
2101  {
2102  /* use user-defined choose method */
2103  FunctionCall2Coll(procinfo,
2104  index->rd_indcollation[0],
2105  PointerGetDatum(&in),
2106  PointerGetDatum(&out));
2107  }
2108  else
2109  {
2110  /* force "match" action (to insert to random subnode) */
2111  out.resultType = spgMatchNode;
2112  }
2113 
2114  if (innerTuple->allTheSame)
2115  {
2116  /*
2117  * It's not allowed to do an AddNode at an allTheSame tuple.
2118  * Opclass must say "match", in which case we choose a random
2119  * one of the nodes to descend into, or "split".
2120  */
2121  if (out.resultType == spgAddNode)
2122  elog(ERROR, "cannot add a node to an allTheSame inner tuple");
2123  else if (out.resultType == spgMatchNode)
2124  out.result.matchNode.nodeN = random() % innerTuple->nNodes;
2125  }
2126 
2127  switch (out.resultType)
2128  {
2129  case spgMatchNode:
2130  /* Descend to N'th child node */
2131  spgMatchNodeAction(index, state, innerTuple,
2132  &current, &parent,
2133  out.result.matchNode.nodeN);
2134  /* Adjust level as per opclass request */
2135  level += out.result.matchNode.levelAdd;
2136  /* Replace leafDatum and recompute leafSize */
2137  if (!isnull)
2138  {
2139  leafDatum = out.result.matchNode.restDatum;
2140  leafSize = SGLTHDRSZ + sizeof(ItemIdData) +
2141  SpGistGetTypeSize(&state->attType, leafDatum);
2142  }
2143 
2144  /*
2145  * Loop around and attempt to insert the new leafDatum at
2146  * "current" (which might reference an existing child
2147  * tuple, or might be invalid to force us to find a new
2148  * page for the tuple).
2149  *
2150  * Note: if the opclass sets longValuesOK, we rely on the
2151  * choose function to eventually shorten the leafDatum
2152  * enough to fit on a page. We could add a test here to
2153  * complain if the datum doesn't get visibly shorter each
2154  * time, but that could get in the way of opclasses that
2155  * "simplify" datums in a way that doesn't necessarily
2156  * lead to physical shortening on every cycle.
2157  */
2158  break;
2159  case spgAddNode:
2160  /* AddNode is not sensible if nodes don't have labels */
2161  if (in.nodeLabels == NULL)
2162  elog(ERROR, "cannot add a node to an inner tuple without node labels");
2163  /* Add node to inner tuple, per request */
2164  spgAddNodeAction(index, state, innerTuple,
2165  &current, &parent,
2166  out.result.addNode.nodeN,
2167  out.result.addNode.nodeLabel);
2168 
2169  /*
2170  * Retry insertion into the enlarged node. We assume that
2171  * we'll get a MatchNode result this time.
2172  */
2173  goto process_inner_tuple;
2174  break;
2175  case spgSplitTuple:
2176  /* Split inner tuple, per request */
2177  spgSplitNodeAction(index, state, innerTuple,
2178  &current, &out);
2179 
2180  /* Retry insertion into the split node */
2181  goto process_inner_tuple;
2182  break;
2183  default:
2184  elog(ERROR, "unrecognized SPGiST choose result: %d",
2185  (int) out.resultType);
2186  break;
2187  }
2188  }
2189  } /* end loop */
2190 
2191  /*
2192  * Release any buffers we're still holding. Beware of possibility that
2193  * current and parent reference same buffer.
2194  */
2195  if (current.buffer != InvalidBuffer)
2196  {
2197  SpGistSetLastUsedPage(index, current.buffer);
2198  UnlockReleaseBuffer(current.buffer);
2199  }
2200  if (parent.buffer != InvalidBuffer &&
2201  parent.buffer != current.buffer)
2202  {
2203  SpGistSetLastUsedPage(index, parent.buffer);
2204  UnlockReleaseBuffer(parent.buffer);
2205  }
2206 
2207  return true;
2208 }
Definition: fmgr.h:56
Datum * spgExtractNodeLabels(SpGistState *state, SpGistInnerTuple innerTuple)
Definition: spgutils.c:804
Datum datum
Definition: spgist.h:56
SpGistInnerTupleData * SpGistInnerTuple
#define SpGistPageIsLeaf(page)
bool hasPrefix
Definition: spgist.h:62
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:58
struct spgChooseOut::@48::@49 matchNode
#define PointerGetDatum(X)
Definition: postgres.h:562
long random(void)
Definition: random.c:22
#define Min(x, y)
Definition: c.h:812
SpGistTypeDesc attType
void SpGistSetLastUsedPage(Relation index, Buffer buffer)
Definition: spgutils.c:476
#define InvalidBuffer
Definition: buf.h:25
Datum prefixDatum
Definition: spgist.h:63
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:1042
#define SPGIST_ROOT_BLKNO
#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:936
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:193
#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:445
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:64
#define SGLTHDRSZ
#define GBUF_LEAF
unsigned int SpGistGetTypeSize(SpGistTypeDesc *att, Datum datum)
Definition: spgutils.c:575
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:231
SpGistLeafTuple spgFormLeafTuple(SpGistState *state, ItemPointer heapPtr, Datum datum, bool isnull)
Definition: spgutils.c:612
bool longValuesOK
Definition: spgist.h:48
uintptr_t Datum
Definition: postgres.h:372
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3546
#define SPGIST_PAGE_CAPACITY
spgChooseResultType resultType
Definition: spgist.h:77
#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:680
Datum leafDatum
Definition: spgist.h:57
struct spgChooseOut::@48::@50 addNode
Buffer SpGistGetBuffer(Relation index, int flags, int needSpace, bool *isNew)
Definition: spgutils.c:371
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:65
int errmsg(const char *fmt,...)
Definition: elog.c:797
bool allTheSame
Definition: spgist.h:61
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:205
#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

◆ spgExtractNodeLabels()

Datum* spgExtractNodeLabels ( SpGistState state,
SpGistInnerTuple  innerTuple 
)

Definition at line 804 of file spgutils.c.

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

Referenced by spgdoinsert(), and spgWalk().

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

◆ spgFormDeadTuple()

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

Definition at line 774 of file spgutils.c.

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

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

776 {
778 
779  tuple->tupstate = tupstate;
780  tuple->size = SGDTSIZE;
782 
783  if (tupstate == SPGIST_REDIRECT)
784  {
785  ItemPointerSet(&tuple->pointer, blkno, offnum);
787  tuple->xid = state->myXid;
788  }
789  else
790  {
792  tuple->xid = InvalidTransactionId;
793  }
794 
795  return tuple;
796 }
#define SGDTSIZE
#define SPGIST_REDIRECT
ItemPointerData pointer
SpGistDeadTupleData * SpGistDeadTuple
#define InvalidTransactionId
Definition: transam.h:31
TransactionId myXid
unsigned int tupstate
char * deadTupleStorage
OffsetNumber nextOffset
#define InvalidOffsetNumber
Definition: off.h:26
#define Assert(condition)
Definition: c.h:680
#define ItemPointerSetInvalid(pointer)
Definition: itemptr.h:150
#define TransactionIdIsValid(xid)
Definition: transam.h:41
#define ItemPointerSet(pointer, blockNumber, offNum)
Definition: itemptr.h:105

◆ spgFormInnerTuple()

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

Definition at line 691 of file spgutils.c.

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

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

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

◆ spgFormLeafTuple()

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

Definition at line 612 of file spgutils.c.

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

Referenced by doPickSplit(), and spgdoinsert().

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

◆ spgFormNodeTuple()

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

Definition at line 649 of file spgutils.c.

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

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

650 {
651  SpGistNodeTuple tup;
652  unsigned int size;
653  unsigned short infomask = 0;
654 
655  /* compute space needed (note result is already maxaligned) */
656  size = SGNTHDRSZ;
657  if (!isnull)
658  size += SpGistGetTypeSize(&state->attLabelType, label);
659 
660  /*
661  * Here we make sure that the size will fit in the field reserved for it
662  * in t_info.
663  */
664  if ((size & INDEX_SIZE_MASK) != size)
665  ereport(ERROR,
666  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
667  errmsg("index row requires %zu bytes, maximum size is %zu",
668  (Size) size, (Size) INDEX_SIZE_MASK)));
669 
670  tup = (SpGistNodeTuple) palloc0(size);
671 
672  if (isnull)
673  infomask |= INDEX_NULL_MASK;
674  /* we don't bother setting the INDEX_VAR_MASK bit */
675  infomask |= size;
676  tup->t_info = infomask;
677 
678  /* The TID field will be filled in later */
680 
681  if (!isnull)
682  memcpyDatum(SGNTDATAPTR(tup), &state->attLabelType, label);
683 
684  return tup;
685 }
ItemPointerData t_tid
Definition: itup.h:37
#define INDEX_SIZE_MASK
Definition: itup.h:65
int errcode(int sqlerrcode)
Definition: elog.c:575
SpGistTypeDesc attLabelType
#define SGNTHDRSZ
#define ERROR
Definition: elog.h:43
#define INDEX_NULL_MASK
Definition: itup.h:68
#define ereport(elevel, rest)
Definition: elog.h:122
unsigned int SpGistGetTypeSize(SpGistTypeDesc *att, Datum datum)
Definition: spgutils.c:575
void * palloc0(Size size)
Definition: mcxt.c:864
static char * label
Definition: pg_basebackup.c:82
#define SGNTDATAPTR(x)
size_t Size
Definition: c.h:414
#define ItemPointerSetInvalid(pointer)
Definition: itemptr.h:150
static void memcpyDatum(void *target, SpGistTypeDesc *att, Datum datum)
Definition: spgutils.c:593
int errmsg(const char *fmt,...)
Definition: elog.c:797
unsigned short t_info
Definition: itup.h:49
SpGistNodeTupleData * SpGistNodeTuple

◆ spgGetCache()

SpGistCache* spgGetCache ( Relation  index)

Definition at line 92 of file spgutils.c.

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

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

93 {
94  SpGistCache *cache;
95 
96  if (index->rd_amcache == NULL)
97  {
98  Oid atttype;
99  spgConfigIn in;
100  FmgrInfo *procinfo;
101  Buffer metabuffer;
102  SpGistMetaPageData *metadata;
103 
104  cache = MemoryContextAllocZero(index->rd_indexcxt,
105  sizeof(SpGistCache));
106 
107  /* SPGiST doesn't support multi-column indexes */
108  Assert(index->rd_att->natts == 1);
109 
110  /*
111  * Get the actual data type of the indexed column from the index
112  * tupdesc. We pass this to the opclass config function so that
113  * polymorphic opclasses are possible.
114  */
115  atttype = TupleDescAttr(index->rd_att, 0)->atttypid;
116 
117  /* Call the config function to get config info for the opclass */
118  in.attType = atttype;
119 
120  procinfo = index_getprocinfo(index, 1, SPGIST_CONFIG_PROC);
121  FunctionCall2Coll(procinfo,
122  index->rd_indcollation[0],
123  PointerGetDatum(&in),
124  PointerGetDatum(&cache->config));
125 
126  /* Get the information we need about each relevant datatype */
127  fillTypeDesc(&cache->attType, atttype);
128  fillTypeDesc(&cache->attPrefixType, cache->config.prefixType);
129  fillTypeDesc(&cache->attLabelType, cache->config.labelType);
130 
131  /* Last, get the lastUsedPages data from the metapage */
132  metabuffer = ReadBuffer(index, SPGIST_METAPAGE_BLKNO);
133  LockBuffer(metabuffer, BUFFER_LOCK_SHARE);
134 
135  metadata = SpGistPageGetMeta(BufferGetPage(metabuffer));
136 
137  if (metadata->magicNumber != SPGIST_MAGIC_NUMBER)
138  elog(ERROR, "index \"%s\" is not an SP-GiST index",
139  RelationGetRelationName(index));
140 
141  cache->lastUsedPages = metadata->lastUsedPages;
142 
143  UnlockReleaseBuffer(metabuffer);
144 
145  index->rd_amcache = (void *) cache;
146  }
147  else
148  {
149  /* assume it's up to date */
150  cache = (SpGistCache *) index->rd_amcache;
151  }
152 
153  return cache;
154 }
Definition: fmgr.h:56
FmgrInfo * index_getprocinfo(Relation irel, AttrNumber attnum, uint16 procnum)
Definition: indexam.c:855
#define PointerGetDatum(X)
Definition: postgres.h:562
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:90
Oid attType
Definition: spgist.h:40
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1042
unsigned int Oid
Definition: postgres_ext.h:31
SpGistTypeDesc attType
int natts
Definition: tupdesc.h:79
SpGistLUPCache lastUsedPages
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3332
Oid * rd_indcollation
Definition: rel.h:193
#define ERROR
Definition: elog.h:43
#define SPGIST_METAPAGE_BLKNO
#define RelationGetRelationName(relation)
Definition: rel.h:445
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
#define SPGIST_MAGIC_NUMBER
spgConfigOut config
SpGistLUPCache lastUsedPages
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3546
Oid prefixType
Definition: spgist.h:45
TupleDesc rd_att
Definition: rel.h:115
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:728
#define Assert(condition)
Definition: c.h:680
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

◆ SpGistGetBuffer()

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

Definition at line 371 of file spgutils.c.

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

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

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

◆ SpGistGetTypeSize()

unsigned int SpGistGetTypeSize ( SpGistTypeDesc att,
Datum  datum 
)

Definition at line 575 of file spgutils.c.

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

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

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

◆ SpGistInitBuffer()

void SpGistInitBuffer ( Buffer  b,
uint16  f 
)

Definition at line 526 of file spgutils.c.

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

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

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

◆ SpGistInitMetapage()

void SpGistInitMetapage ( Page  page)

Definition at line 536 of file spgutils.c.

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

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

537 {
538  SpGistMetaPageData *metadata;
539  int i;
540 
542  metadata = SpGistPageGetMeta(page);
543  memset(metadata, 0, sizeof(SpGistMetaPageData));
544  metadata->magicNumber = SPGIST_MAGIC_NUMBER;
545 
546  /* initialize last-used-page cache to empty */
547  for (i = 0; i < SPGIST_CACHED_PAGES; i++)
549 
550  /*
551  * Set pd_lower just past the end of the metadata. This is essential,
552  * because without doing so, metadata will be lost if xlog.c compresses
553  * the page.
554  */
555  ((PageHeader) page)->pd_lower =
556  ((char *) metadata + sizeof(SpGistMetaPageData)) - (char *) page;
557 }
SpGistLastUsedPage cachedPage[SPGIST_CACHED_PAGES]
#define SPGIST_META
#define SPGIST_MAGIC_NUMBER
SpGistLUPCache lastUsedPages
#define InvalidBlockNumber
Definition: block.h:33
#define SPGIST_CACHED_PAGES
#define SpGistPageGetMeta(p)
void SpGistInitPage(Page page, uint16 f)
Definition: spgutils.c:511
int i

◆ SpGistInitPage()

void SpGistInitPage ( Page  page,
uint16  f 
)

Definition at line 511 of file spgutils.c.

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

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

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

◆ SpGistNewBuffer()

Buffer SpGistNewBuffer ( Relation  index)

Definition at line 187 of file spgutils.c.

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

Referenced by allocNewBuffer(), and spgbuild().

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

◆ SpGistPageAddNewItem()

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

Definition at line 847 of file spgutils.c.

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

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

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

◆ SpGistSetLastUsedPage()

void SpGistSetLastUsedPage ( Relation  index,
Buffer  buffer 
)

Definition at line 476 of file spgutils.c.

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

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

477 {
478  SpGistCache *cache = spgGetCache(index);
479  SpGistLastUsedPage *lup;
480  int freeSpace;
481  Page page = BufferGetPage(buffer);
483  int flags;
484 
485  /* Never enter fixed pages (root pages) in cache, though */
486  if (SpGistBlockIsFixed(blkno))
487  return;
488 
489  if (SpGistPageIsLeaf(page))
490  flags = GBUF_LEAF;
491  else
492  flags = GBUF_INNER_PARITY(blkno);
493  if (SpGistPageStoresNulls(page))
494  flags |= GBUF_NULLS;
495 
496  lup = GET_LUP(cache, flags);
497 
498  freeSpace = PageGetExactFreeSpace(page);
499  if (lup->blkno == InvalidBlockNumber || lup->blkno == blkno ||
500  lup->freeSpace < freeSpace)
501  {
502  lup->blkno = blkno;
503  lup->freeSpace = freeSpace;
504  }
505 }
#define SpGistPageIsLeaf(page)
SpGistCache * spgGetCache(Relation index)
Definition: spgutils.c:92
#define GET_LUP(c, f)
Definition: spgutils.c:292
uint32 BlockNumber
Definition: block.h:31
#define GBUF_INNER_PARITY(x)
#define SpGistBlockIsFixed(blkno)
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
#define GBUF_LEAF
#define SpGistPageStoresNulls(page)
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:214
#define InvalidBlockNumber
Definition: block.h:33
#define GBUF_NULLS
Size PageGetExactFreeSpace(Page page)
Definition: bufpage.c:629
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2605
Pointer Page
Definition: bufpage.h:74

◆ SpGistUpdateMetaPage()

void SpGistUpdateMetaPage ( Relation  index)

Definition at line 252 of file spgutils.c.

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

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

253 {
254  SpGistCache *cache = (SpGistCache *) index->rd_amcache;
255 
256  if (cache != NULL)
257  {
258  Buffer metabuffer;
259 
260  metabuffer = ReadBuffer(index, SPGIST_METAPAGE_BLKNO);
261 
262  if (ConditionalLockBuffer(metabuffer))
263  {
264  Page metapage = BufferGetPage(metabuffer);
265  SpGistMetaPageData *metadata = SpGistPageGetMeta(metapage);
266 
267  metadata->lastUsedPages = cache->lastUsedPages;
268 
269  /*
270  * Set pd_lower just past the end of the metadata. This is
271  * essential, because without doing so, metadata will be lost if
272  * xlog.c compresses the page. (We must do this here because
273  * pre-v11 versions of PG did not set the metapage's pd_lower
274  * correctly, so a pg_upgraded index might contain the wrong
275  * value.)
276  */
277  ((PageHeader) metapage)->pd_lower =
278  ((char *) metadata + sizeof(SpGistMetaPageData)) - (char *) metapage;
279 
280  MarkBufferDirty(metabuffer);
281  UnlockReleaseBuffer(metabuffer);
282  }
283  else
284  {
285  ReleaseBuffer(metabuffer);
286  }
287  }
288 }
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1450
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3309
SpGistLUPCache lastUsedPages
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3332
#define SPGIST_METAPAGE_BLKNO
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
bool ConditionalLockBuffer(Buffer buffer)
Definition: bufmgr.c:3572
SpGistLUPCache lastUsedPages
PageHeaderData * PageHeader
Definition: bufpage.h:162
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:594
#define SpGistPageGetMeta(p)
void * rd_amcache
Definition: rel.h:192
int Buffer
Definition: buf.h:23
Pointer Page
Definition: bufpage.h:74

◆ 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:774
#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:137
int i
#define elog
Definition: elog.h:219
#define qsort(a, b, c, d)
Definition: port.h:408
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:105