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

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

Definition at line 229 of file spgist_private.h.

#define GBUF_INNER_PARITY (   x)    ((x) % 3)
#define GBUF_LEAF   0x03

Definition at line 374 of file spgist_private.h.

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

#define GBUF_NULLS   0x04
#define GBUF_PARITY_MASK   0x03

Definition at line 378 of file spgist_private.h.

Referenced by allocNewBuffer().

#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().

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

Definition at line 380 of file spgist_private.h.

Referenced by allocNewBuffer(), and SpGistGetBuffer().

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

Definition at line 230 of file spgist_private.h.

Referenced by spgFormInnerTuple().

#define SGITDATUM (   x,
 
)
Value:
((x)->prefixSize ? \
((s)->attPrefixType.attbyval ? \
*(Datum *) _SGITDATA(x) : \
: (Datum) 0)
#define PointerGetDatum(X)
Definition: postgres.h:562
#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().

#define SGITHDRSZ   MAXALIGN(sizeof(SpGistInnerTupleData))

Definition at line 228 of file spgist_private.h.

Referenced by spgFormInnerTuple().

#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().

#define SGITMAXNNODES   0x1FFF

Definition at line 224 of file spgist_private.h.

Referenced by spgFormInnerTuple(), and spgSplitNodeAction().

#define SGITMAXPREFIXSIZE   0xFFFF

Definition at line 225 of file spgist_private.h.

Referenced by spgFormInnerTuple().

#define SGITMAXSIZE   0xFFFF

Definition at line 226 of file spgist_private.h.

Referenced by spgFormInnerTuple().

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

Definition at line 236 of file spgist_private.h.

Referenced by spgExtractNodeLabels(), and spgFormInnerTuple().

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

Definition at line 302 of file spgist_private.h.

Referenced by spgFormLeafTuple().

#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().

#define SGLTHDRSZ   MAXALIGN(sizeof(SpGistLeafTupleData))

Definition at line 301 of file spgist_private.h.

Referenced by spgdoinsert(), and spgFormLeafTuple().

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

Definition at line 259 of file spgist_private.h.

Referenced by spgFormNodeTuple().

#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().

#define SGNTHDRSZ   MAXALIGN(sizeof(SpGistNodeTupleData))

Definition at line 258 of file spgist_private.h.

Referenced by spgFormNodeTuple().

#define SPGIST_CACHED_PAGES   8

Definition at line 84 of file spgist_private.h.

Referenced by SpGistInitMetapage().

#define SPGIST_DEAD   2 /* dead, cannot be removed because of links */
#define SPGIST_DELETED
Value:
(1<<1) /* never set, but keep for backwards
* compatibility */

Definition at line 51 of file spgist_private.h.

#define SPGIST_LAST_FIXED_BLKNO   SPGIST_NULL_BLKNO

Definition at line 28 of file spgist_private.h.

Referenced by spgvacuumscan().

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

Definition at line 100 of file spgist_private.h.

Referenced by spgGetCache(), and SpGistInitMetapage().

#define SPGIST_META   (1<<0)

Definition at line 50 of file spgist_private.h.

Referenced by SpGistInitMetapage().

#define SPGIST_METAPAGE_BLKNO   (0) /* metapage */
#define SPGIST_NULL_BLKNO   (2) /* root for null-value entries */
#define SPGIST_PAGE_CAPACITY
Value:
MAXALIGN_DOWN(BLCKSZ - \
#define SizeOfPageHeaderData
Definition: bufpage.h:213
#define MAXALIGN(LEN)
Definition: c.h:588
#define MAXALIGN_DOWN(LEN)
Definition: c.h:600

Definition at line 339 of file spgist_private.h.

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

#define SPGIST_PAGE_ID   0xFF82

Definition at line 70 of file spgist_private.h.

Referenced by SpGistInitPage().

#define SPGIST_ROOT_BLKNO   (1) /* root for normal entries */
#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().

#define SpGistBlockIsRoot (   blkno)    ((blkno) == SPGIST_ROOT_BLKNO || (blkno) == SPGIST_NULL_BLKNO)
#define SpGistPageGetFreeSpace (   p,
 
)
Value:
Min(SpGistPageGetOpaque(p)->nPlaceholder, n) * \
(SGDTSIZE + sizeof(ItemIdData)))
#define SGDTSIZE
#define Min(x, y)
Definition: c.h:806
struct ItemIdData ItemIdData
Size PageGetExactFreeSpace(Page page)
Definition: bufpage.c:633
#define SpGistPageGetOpaque(page)

Definition at line 348 of file spgist_private.h.

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

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

Definition at line 102 of file spgist_private.h.

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

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

Definition at line 58 of file spgist_private.h.

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

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

Definition at line 57 of file spgist_private.h.

Referenced by spg_mask().

#define SpGistPageStoresNulls (   page)    (SpGistPageGetOpaque(page)->flags & SPGIST_NULLS)
#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

Function Documentation

void initSpGistState ( SpGistState state,
Relation  index 
)

Definition at line 158 of file spgutils.c.

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

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

159 {
160  SpGistCache *cache;
161 
162  /* Get cached static information about index */
163  cache = spgGetCache(index);
164 
165  state->config = cache->config;
166  state->attType = cache->attType;
167  state->attPrefixType = cache->attPrefixType;
168  state->attLabelType = cache->attLabelType;
169 
170  /* Make workspace for constructing dead tuples */
172 
173  /* Set XID to use in redirection tuples */
174  state->myXid = GetTopTransactionIdIfAny();
175 
176  /* Assume we're not in an index build (spgbuild will override) */
177  state->isBuild = false;
178 }
SpGistTypeDesc attPrefixType
SpGistCache * spgGetCache(Relation index)
Definition: spgutils.c:92
#define SGDTSIZE
SpGistTypeDesc attType
SpGistTypeDesc attLabelType
SpGistTypeDesc attType
spgConfigOut config
TransactionId myXid
TransactionId GetTopTransactionIdIfAny(void)
Definition: xact.c:404
spgConfigOut config
void * palloc0(Size size)
Definition: mcxt.c:878
char * deadTupleStorage
SpGistTypeDesc attLabelType
SpGistTypeDesc attPrefixType
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, NULL, 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:53
Datum * spgExtractNodeLabels(SpGistState *state, SpGistInnerTuple innerTuple)
Definition: spgutils.c:784
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
#define PointerGetDatum(X)
Definition: postgres.h:562
long random(void)
Definition: random.c:22
#define Min(x, y)
Definition: c.h:806
SpGistTypeDesc attType
void SpGistSetLastUsedPage(Relation index, Buffer buffer)
Definition: spgutils.c:464
#define InvalidBuffer
Definition: buf.h:25
Datum prefixDatum
Definition: spgist.h:63
int errcode(int sqlerrcode)
Definition: elog.c:575
union spgChooseOut::@42 result
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:1356
#define SPGIST_ROOT_BLKNO
struct spgChooseOut::@42::@44 addNode
#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:950
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:189
#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:433
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:555
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:232
SpGistLeafTuple spgFormLeafTuple(SpGistState *state, ItemPointer heapPtr, Datum datum, bool isnull)
Definition: spgutils.c:592
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)
struct spgChooseOut::@42::@43 matchNode
static void spgMatchNodeAction(Relation index, SpGistState *state, SpGistInnerTuple innerTuple, SPPageDesc *current, SPPageDesc *parent, int nodeN)
Definition: spgdoinsert.c:1436
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
Datum leafDatum
Definition: spgist.h:57
Buffer SpGistGetBuffer(Relation index, int flags, int needSpace, bool *isNew)
Definition: spgutils.c:359
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:594
#define InvalidBlockNumber
Definition: block.h:33
#define GBUF_NULLS
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:197
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:97
#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:337
BlockNumber blkno
Definition: spgdoinsert.c:36
Datum* spgExtractNodeLabels ( SpGistState state,
SpGistInnerTuple  innerTuple 
)

Definition at line 784 of file spgutils.c.

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

Referenced by spgdoinsert(), and spgWalk().

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

Definition at line 754 of file spgutils.c.

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

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

756 {
758 
759  tuple->tupstate = tupstate;
760  tuple->size = SGDTSIZE;
762 
763  if (tupstate == SPGIST_REDIRECT)
764  {
765  ItemPointerSet(&tuple->pointer, blkno, offnum);
767  tuple->xid = state->myXid;
768  }
769  else
770  {
772  tuple->xid = InvalidTransactionId;
773  }
774 
775  return tuple;
776 }
#define SGDTSIZE
#define SPGIST_REDIRECT
ItemPointerData pointer
SpGistDeadTupleData * SpGistDeadTuple
#define InvalidTransactionId
Definition: transam.h:31
TransactionId myXid
unsigned int tupstate
char * deadTupleStorage
OffsetNumber nextOffset
#define InvalidOffsetNumber
Definition: off.h:26
#define Assert(condition)
Definition: c.h:675
#define ItemPointerSetInvalid(pointer)
Definition: itemptr.h:131
#define TransactionIdIsValid(xid)
Definition: transam.h:41
#define ItemPointerSet(pointer, blockNumber, offNum)
Definition: itemptr.h:86
SpGistInnerTuple spgFormInnerTuple ( SpGistState state,
bool  hasPrefix,
Datum  prefix,
int  nNodes,
SpGistNodeTuple nodes 
)

Definition at line 671 of file spgutils.c.

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

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

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

Definition at line 592 of file spgutils.c.

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

Referenced by doPickSplit(), and spgdoinsert().

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

Definition at line 629 of file spgutils.c.

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

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

630 {
631  SpGistNodeTuple tup;
632  unsigned int size;
633  unsigned short infomask = 0;
634 
635  /* compute space needed (note result is already maxaligned) */
636  size = SGNTHDRSZ;
637  if (!isnull)
638  size += SpGistGetTypeSize(&state->attLabelType, label);
639 
640  /*
641  * Here we make sure that the size will fit in the field reserved for it
642  * in t_info.
643  */
644  if ((size & INDEX_SIZE_MASK) != size)
645  ereport(ERROR,
646  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
647  errmsg("index row requires %zu bytes, maximum size is %zu",
648  (Size) size, (Size) INDEX_SIZE_MASK)));
649 
650  tup = (SpGistNodeTuple) palloc0(size);
651 
652  if (isnull)
653  infomask |= INDEX_NULL_MASK;
654  /* we don't bother setting the INDEX_VAR_MASK bit */
655  infomask |= size;
656  tup->t_info = infomask;
657 
658  /* The TID field will be filled in later */
660 
661  if (!isnull)
662  memcpyDatum(SGNTDATAPTR(tup), &state->attLabelType, label);
663 
664  return tup;
665 }
ItemPointerData t_tid
Definition: itup.h:37
#define INDEX_SIZE_MASK
Definition: itup.h:65
int errcode(int sqlerrcode)
Definition: elog.c:575
SpGistTypeDesc attLabelType
#define SGNTHDRSZ
#define ERROR
Definition: elog.h:43
#define INDEX_NULL_MASK
Definition: itup.h:68
#define ereport(elevel, rest)
Definition: elog.h:122
unsigned int SpGistGetTypeSize(SpGistTypeDesc *att, Datum datum)
Definition: spgutils.c:555
void * palloc0(Size size)
Definition: mcxt.c:878
static char * label
Definition: pg_basebackup.c:81
#define SGNTDATAPTR(x)
size_t Size
Definition: c.h:356
#define ItemPointerSetInvalid(pointer)
Definition: itemptr.h:131
static void memcpyDatum(void *target, SpGistTypeDesc *att, Datum datum)
Definition: spgutils.c:573
int errmsg(const char *fmt,...)
Definition: elog.c:797
unsigned short t_info
Definition: itup.h:49
SpGistNodeTupleData * SpGistNodeTuple
SpGistCache* spgGetCache ( Relation  index)

Definition at line 92 of file spgutils.c.

References Assert, SpGistCache::attLabelType, SpGistCache::attPrefixType, tupleDesc::attrs, spgConfigIn::attType, SpGistCache::attType, BUFFER_LOCK_SHARE, BufferGetPage, SpGistCache::config, elog, ERROR, fillTypeDesc(), FunctionCall2Coll(), index_getprocinfo(), spgConfigOut::labelType, SpGistMetaPageData::lastUsedPages, SpGistCache::lastUsedPages, LockBuffer(), SpGistMetaPageData::magicNumber, MemoryContextAllocZero(), tupleDesc::natts, NULL, PointerGetDatum, spgConfigOut::prefixType, RelationData::rd_amcache, RelationData::rd_att, RelationData::rd_indcollation, RelationData::rd_indexcxt, ReadBuffer(), RelationGetRelationName, SPGIST_CONFIG_PROC, SPGIST_MAGIC_NUMBER, SPGIST_METAPAGE_BLKNO, SpGistPageGetMeta, 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 = index->rd_att->attrs[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:53
FmgrInfo * index_getprocinfo(Relation irel, AttrNumber attnum, uint16 procnum)
Definition: indexam.c:855
#define PointerGetDatum(X)
Definition: postgres.h:562
Form_pg_attribute * attrs
Definition: tupdesc.h:74
Oid attType
Definition: spgist.h:40
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1356
unsigned int Oid
Definition: postgres_ext.h:31
SpGistTypeDesc attType
int natts
Definition: tupdesc.h:73
SpGistLUPCache lastUsedPages
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3332
Oid * rd_indcollation
Definition: rel.h:189
#define ERROR
Definition: elog.h:43
#define SPGIST_METAPAGE_BLKNO
#define RelationGetRelationName(relation)
Definition: rel.h:433
#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:114
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:742
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
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:175
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:188
int Buffer
Definition: buf.h:23
Buffer SpGistGetBuffer ( Relation  index,
int  flags,
int  needSpace,
bool isNew 
)

Definition at line 359 of file spgutils.c.

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

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

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

Definition at line 555 of file spgutils.c.

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

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

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

Definition at line 514 of file spgutils.c.

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

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

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

Definition at line 524 of file spgutils.c.

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

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

525 {
526  SpGistMetaPageData *metadata;
527  int i;
528 
530  metadata = SpGistPageGetMeta(page);
531  memset(metadata, 0, sizeof(SpGistMetaPageData));
532  metadata->magicNumber = SPGIST_MAGIC_NUMBER;
533 
534  /* initialize last-used-page cache to empty */
535  for (i = 0; i < SPGIST_CACHED_PAGES; i++)
537 }
SpGistLastUsedPage cachedPage[SPGIST_CACHED_PAGES]
#define SPGIST_META
#define SPGIST_MAGIC_NUMBER
SpGistLUPCache lastUsedPages
#define InvalidBlockNumber
Definition: block.h:33
#define SPGIST_CACHED_PAGES
#define SpGistPageGetMeta(p)
void SpGistInitPage(Page page, uint16 f)
Definition: spgutils.c:499
int i
void SpGistInitPage ( Page  page,
uint16  f 
)

Definition at line 499 of file spgutils.c.

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

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

500 {
501  SpGistPageOpaque opaque;
502 
503  PageInit(page, BLCKSZ, MAXALIGN(sizeof(SpGistPageOpaqueData)));
504  opaque = SpGistPageGetOpaque(page);
505  memset(opaque, 0, sizeof(SpGistPageOpaqueData));
506  opaque->flags = f;
507  opaque->spgist_page_id = SPGIST_PAGE_ID;
508 }
#define SPGIST_PAGE_ID
#define MAXALIGN(LEN)
Definition: c.h:588
#define SpGistPageGetOpaque(page)
void PageInit(Page page, Size pageSize, Size specialSize)
Definition: bufpage.c:41
Buffer SpGistNewBuffer ( Relation  index)

Definition at line 187 of file spgutils.c.

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

Referenced by allocNewBuffer(), and spgbuild().

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

Definition at line 827 of file spgutils.c.

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

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

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

Definition at line 464 of file spgutils.c.

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

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

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

Definition at line 252 of file spgutils.c.

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

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

253 {
254  SpGistCache *cache = (SpGistCache *) index->rd_amcache;
255 
256  if (cache != NULL)
257  {
258  Buffer metabuffer;
259  SpGistMetaPageData *metadata;
260 
261  metabuffer = ReadBuffer(index, SPGIST_METAPAGE_BLKNO);
262 
263  if (ConditionalLockBuffer(metabuffer))
264  {
265  metadata = SpGistPageGetMeta(BufferGetPage(metabuffer));
266  metadata->lastUsedPages = cache->lastUsedPages;
267 
268  MarkBufferDirty(metabuffer);
269  UnlockReleaseBuffer(metabuffer);
270  }
271  else
272  {
273  ReleaseBuffer(metabuffer);
274  }
275  }
276 }
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1450
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3309
SpGistLUPCache lastUsedPages
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3332
#define SPGIST_METAPAGE_BLKNO
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
bool ConditionalLockBuffer(Buffer buffer)
Definition: bufmgr.c:3572
SpGistLUPCache lastUsedPages
#define NULL
Definition: c.h:229
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:594
#define SpGistPageGetMeta(p)
void * rd_amcache
Definition: rel.h:188
int Buffer
Definition: buf.h:23
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, NULL, 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:754
#define SPGIST_REDIRECT
#define SPGIST_PLACEHOLDER
Pointer Item
Definition: item.h:17
#define PageAddItem(page, item, size, offsetNumber, overwrite, is_heap)
Definition: bufpage.h:413
uint16 OffsetNumber
Definition: off.h:24
#define ERROR
Definition: elog.h:43
unsigned int tupstate
#define NULL
Definition: c.h:229
void PageIndexMultiDelete(Page page, OffsetNumber *itemnos, int nitems)
Definition: bufpage.c:836
#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:440
static int cmpOffsetNumbers(const void *a, const void *b)
Definition: spgdoinsert.c:110
void spgUpdateNodeLink ( SpGistInnerTuple  tup,
int  nodeN,
BlockNumber  blkno,
OffsetNumber  offset 
)

Definition at line 50 of file spgdoinsert.c.

References elog, ERROR, i, ItemPointerSet, 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:86