#include "access/itup.h"#include "access/spgist.h"#include "nodes/tidbitmap.h"#include "storage/relfilenode.h"#include "utils/relcache.h"

Go to the source code of this file.
| #define _SGITDATA | ( | x | ) | (((char *) (x)) + SGITHDRSZ) |
Definition at line 227 of file spgist_private.h.
| #define ACCEPT_RDATA_BUFFER | ( | b, | ||
| i | ||||
| ) |
do { \ Assert((i) < lengthof(rdata)); \ rdata[i].data = NULL; \ rdata[i].len = 0; \ rdata[i].buffer = (b); \ rdata[i].buffer_std = true; \ rdata[i].next = NULL; \ if ((i) > 0) \ rdata[(i) - 1].next = rdata + (i); \ } while(0)
Definition at line 369 of file spgist_private.h.
Referenced by addLeafTuple(), doPickSplit(), moveLeafs(), spgAddNodeAction(), spgSplitNodeAction(), vacuumLeafPage(), vacuumLeafRoot(), and vacuumRedirectAndPlaceholder().
| #define ACCEPT_RDATA_DATA | ( | p, | ||
| s, | ||||
| i | ||||
| ) |
do { \ Assert((i) < lengthof(rdata)); \ rdata[i].data = (char *) (p); \ rdata[i].len = (s); \ rdata[i].buffer = InvalidBuffer; \ rdata[i].buffer_std = true; \ rdata[i].next = NULL; \ if ((i) > 0) \ rdata[(i) - 1].next = rdata + (i); \ } while(0)
Definition at line 357 of file spgist_private.h.
Referenced by addLeafTuple(), doPickSplit(), moveLeafs(), spgAddNodeAction(), spgSplitNodeAction(), vacuumLeafPage(), vacuumLeafRoot(), and vacuumRedirectAndPlaceholder().
| #define GBUF_INNER_PARITY | ( | x | ) | ((x) % 3) |
Definition at line 612 of file spgist_private.h.
Referenced by allocNewBuffer(), doPickSplit(), spgAddNodeAction(), SpGistSetLastUsedPage(), and spgSplitNodeAction().
| #define GBUF_LEAF 0x03 |
Definition at line 611 of file spgist_private.h.
Referenced by doPickSplit(), moveLeafs(), and spgdoinsert().
| #define GBUF_NULLS 0x04 |
Definition at line 613 of file spgist_private.h.
Referenced by doPickSplit(), moveLeafs(), and spgdoinsert().
| #define GBUF_PARITY_MASK 0x03 |
Definition at line 615 of file spgist_private.h.
Referenced by allocNewBuffer().
| #define GBUF_REQ_LEAF | ( | flags | ) | (((flags) & GBUF_PARITY_MASK) == GBUF_LEAF) |
Definition at line 616 of file spgist_private.h.
Referenced by allocNewBuffer(), and SpGistGetBuffer().
| #define GBUF_REQ_NULLS | ( | flags | ) | ((flags) & GBUF_NULLS) |
Definition at line 617 of file spgist_private.h.
Referenced by allocNewBuffer(), and SpGistGetBuffer().
| #define SGDTSIZE MAXALIGN(sizeof(SpGistDeadTupleData)) |
Definition at line 327 of file spgist_private.h.
Referenced by doPickSplit(), fillFakeState(), initSpGistState(), spgdoinsert(), spgFormDeadTuple(), spgFormInnerTuple(), spgFormLeafTuple(), and SpGistPageAddNewItem().
| #define SGITDATAPTR | ( | x | ) | ((x)->prefixSize ? _SGITDATA(x) : NULL) |
Definition at line 228 of file spgist_private.h.
Referenced by spgFormInnerTuple().
| #define SGITDATUM | ( | x, | ||
| s | ||||
| ) |
((x)->prefixSize ? \
((s)->attPrefixType.attbyval ? \
*(Datum *) _SGITDATA(x) : \
PointerGetDatum(_SGITDATA(x))) \
: (Datum) 0)
Definition at line 229 of file spgist_private.h.
Referenced by addNode(), spgdoinsert(), and spgWalk().
| #define SGITHDRSZ MAXALIGN(sizeof(SpGistInnerTupleData)) |
Definition at line 226 of file spgist_private.h.
Referenced by spgFormInnerTuple().
| #define SGITITERATE | ( | x, | ||
| i, | ||||
| nt | ||||
| ) |
for ((i) = 0, (nt) = SGITNODEPTR(x); \ (i) < (x)->nNodes; \ (i)++, (nt) = (SpGistNodeTuple) (((char *) (nt)) + IndexTupleSize(nt)))
Definition at line 237 of file spgist_private.h.
Referenced by addNode(), doPickSplit(), spgExtractNodeLabels(), spgMatchNodeAction(), spgprocesspending(), spgSplitNodeAction(), spgUpdateNodeLink(), and spgWalk().
| #define SGITMAXNNODES 0x1FFF |
Definition at line 222 of file spgist_private.h.
Referenced by spgFormInnerTuple().
| #define SGITMAXPREFIXSIZE 0xFFFF |
Definition at line 223 of file spgist_private.h.
Referenced by spgFormInnerTuple().
| #define SGITMAXSIZE 0xFFFF |
Definition at line 224 of file spgist_private.h.
Referenced by spgFormInnerTuple().
| #define SGITNODEPTR | ( | x | ) | ((SpGistNodeTuple) (_SGITDATA(x) + (x)->prefixSize)) |
Definition at line 234 of file spgist_private.h.
Referenced by spgExtractNodeLabels(), and spgFormInnerTuple().
| #define SGLTDATAPTR | ( | x | ) | (((char *) (x)) + SGLTHDRSZ) |
Definition at line 300 of file spgist_private.h.
Referenced by spgFormLeafTuple().
| #define SGLTDATUM | ( | x, | ||
| s | ||||
| ) |
((s)->attType.attbyval ? \
*(Datum *) SGLTDATAPTR(x) : \
PointerGetDatum(SGLTDATAPTR(x)))
Definition at line 301 of file spgist_private.h.
Referenced by doPickSplit(), and spgLeafTest().
| #define SGLTHDRSZ MAXALIGN(sizeof(SpGistLeafTupleData)) |
Definition at line 299 of file spgist_private.h.
Referenced by spgdoinsert().
| #define SGNTDATAPTR | ( | x | ) | (((char *) (x)) + SGNTHDRSZ) |
Definition at line 257 of file spgist_private.h.
Referenced by spgFormNodeTuple().
| #define SGNTDATUM | ( | x, | ||
| s | ||||
| ) |
((s)->attLabelType.attbyval ? \
*(Datum *) SGNTDATAPTR(x) : \
PointerGetDatum(SGNTDATAPTR(x)))
Definition at line 258 of file spgist_private.h.
Referenced by spgExtractNodeLabels().
| #define SGNTHDRSZ MAXALIGN(sizeof(SpGistNodeTupleData)) |
Definition at line 256 of file spgist_private.h.
| #define SPGIST_CACHED_PAGES 8 |
Definition at line 82 of file spgist_private.h.
| #define SPGIST_DEAD 2 |
Definition at line 197 of file spgist_private.h.
Referenced by addLeafTuple(), checkSplitConditions(), doPickSplit(), moveLeafs(), spgRedoVacuumLeaf(), spgWalk(), and vacuumLeafPage().
| #define SPGIST_DELETED (1<<1) |
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.
| #define SPGIST_LEAF (1<<2) |
Definition at line 52 of file spgist_private.h.
Referenced by allocNewBuffer(), doPickSplit(), spgbuild(), spgbuildempty(), spgRedoAddLeaf(), spgRedoCreateIndex(), spgRedoMoveLeafs(), and spgRedoPickSplit().
| #define SPGIST_LIVE 0 |
Definition at line 195 of file spgist_private.h.
Referenced by addLeafTuple(), checkSplitConditions(), doPickSplit(), moveLeafs(), spgprocesspending(), spgRedoVacuumLeaf(), spgWalk(), vacuumLeafPage(), and vacuumLeafRoot().
| #define SPGIST_MAGIC_NUMBER (0xBA0BABEE) |
Definition at line 98 of file spgist_private.h.
Referenced by spgGetCache().
| #define SPGIST_META (1<<0) |
Definition at line 50 of file spgist_private.h.
Referenced by SpGistInitMetapage().
| #define SPGIST_METAPAGE_BLKNO (0) |
Definition at line 25 of file spgist_private.h.
Referenced by doPickSplit(), setRedirectionTuple(), spgbuild(), spgbuildempty(), spgGetCache(), SpGistUpdateMetaPage(), spgRedoCreateIndex(), spgvacuumscan(), and spgWalk().
| #define SPGIST_NULL_BLKNO (2) |
Definition at line 27 of file spgist_private.h.
Referenced by resetSpGistScanOpaque(), spgbuild(), spgbuildempty(), spgdoinsert(), and spgRedoCreateIndex().
| #define SPGIST_NULLS (1<<3) |
Definition at line 53 of file spgist_private.h.
Referenced by allocNewBuffer(), doPickSplit(), spgbuild(), spgbuildempty(), spgRedoAddLeaf(), spgRedoCreateIndex(), spgRedoMoveLeafs(), and spgRedoPickSplit().
| #define SPGIST_PAGE_CAPACITY |
MAXALIGN_DOWN(BLCKSZ - \ SizeOfPageHeaderData - \ MAXALIGN(sizeof(SpGistPageOpaqueData)))
Definition at line 337 of file spgist_private.h.
Referenced by doPickSplit(), spgdoinsert(), spgFormInnerTuple(), and SpGistGetBuffer().
| #define SPGIST_PAGE_ID 0xFF82 |
Definition at line 68 of file spgist_private.h.
| #define SPGIST_PLACEHOLDER 3 |
Definition at line 198 of file spgist_private.h.
Referenced by addOrReplaceTuple(), doPickSplit(), moveLeafs(), spgAddNodeAction(), SpGistPageAddNewItem(), spgPageIndexMultiDelete(), spgRedoAddNode(), spgRedoMoveLeafs(), spgRedoPickSplit(), spgRedoVacuumLeaf(), vacuumLeafPage(), and vacuumRedirectAndPlaceholder().
| #define SPGIST_REDIRECT 1 |
Definition at line 196 of file spgist_private.h.
Referenced by doPickSplit(), moveLeafs(), setRedirectionTuple(), spgAddNodeAction(), spgFormDeadTuple(), spgPageIndexMultiDelete(), spgprocesspending(), spgRedoAddNode(), spgRedoMoveLeafs(), spgRedoPickSplit(), spgRedoVacuumRedirect(), spgWalk(), vacuumLeafPage(), and vacuumRedirectAndPlaceholder().
| #define SPGIST_ROOT_BLKNO (1) |
Definition at line 26 of file spgist_private.h.
Referenced by resetSpGistScanOpaque(), spgbuild(), spgbuildempty(), and spgRedoCreateIndex().
| #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) |
Definition at line 30 of file spgist_private.h.
Referenced by addLeafTuple(), checkSplitConditions(), doPickSplit(), spgAddNodeAction(), spgprocesspending(), spgRedoPickSplit(), spgSplitNodeAction(), spgvacuumpage(), and spgWalk().
| #define SpGistPageGetFreeSpace | ( | p, | ||
| n | ||||
| ) |
(PageGetExactFreeSpace(p) + \ Min(SpGistPageGetOpaque(p)->nPlaceholder, n) * \ (SGDTSIZE + sizeof(ItemIdData)))
Definition at line 346 of file spgist_private.h.
Referenced by doPickSplit(), spgdoinsert(), and spgSplitNodeAction().
| #define SpGistPageGetMeta | ( | p | ) | ((SpGistMetaPageData *) PageGetContents(p)) |
Definition at line 100 of file spgist_private.h.
Referenced by spgGetCache(), SpGistInitMetapage(), and SpGistUpdateMetaPage().
| #define SpGistPageGetOpaque | ( | page | ) | ((SpGistPageOpaque) PageGetSpecialPointer(page)) |
Definition at line 55 of file spgist_private.h.
Referenced by addOrReplaceTuple(), doPickSplit(), spgAddNodeAction(), SpGistInitPage(), SpGistPageAddNewItem(), spgPageIndexMultiDelete(), spgRedoAddNode(), spgRedoVacuumRedirect(), and vacuumRedirectAndPlaceholder().
| #define SpGistPageIsDeleted | ( | page | ) | (SpGistPageGetOpaque(page)->flags & SPGIST_DELETED) |
Definition at line 57 of file spgist_private.h.
Referenced by SpGistGetBuffer(), SpGistNewBuffer(), spgprocesspending(), and spgvacuumpage().
| #define SpGistPageIsLeaf | ( | page | ) | (SpGistPageGetOpaque(page)->flags & SPGIST_LEAF) |
Definition at line 59 of file spgist_private.h.
Referenced by spgdoinsert(), SpGistGetBuffer(), SpGistSetLastUsedPage(), spgprocesspending(), spgvacuumpage(), and spgWalk().
| #define SpGistPageIsMeta | ( | page | ) | (SpGistPageGetOpaque(page)->flags & SPGIST_META) |
Definition at line 56 of file spgist_private.h.
| #define SpGistPageSetDeleted | ( | page | ) | (SpGistPageGetOpaque(page)->flags |= SPGIST_DELETED) |
Definition at line 58 of file spgist_private.h.
Referenced by spgvacuumpage().
| #define SpGistPageStoresNulls | ( | page | ) | (SpGistPageGetOpaque(page)->flags & SPGIST_NULLS) |
Definition at line 60 of file spgist_private.h.
Referenced by spgAddNodeAction(), spgdoinsert(), SpGistGetBuffer(), SpGistSetLastUsedPage(), spgSplitNodeAction(), and spgWalk().
| #define STORE_STATE | ( | s, | ||
| d | ||||
| ) |
do { \ (d).myXid = (s)->myXid; \ (d).isBuild = (s)->isBuild; \ } while(0)
Definition at line 404 of file spgist_private.h.
Referenced by doPickSplit(), moveLeafs(), spgAddNodeAction(), vacuumLeafPage(), and vacuumLeafRoot().
| #define XLOG_SPGIST_ADD_LEAF 0x10 |
Definition at line 384 of file spgist_private.h.
Referenced by addLeafTuple(), spg_desc(), and spg_redo().
| #define XLOG_SPGIST_ADD_NODE 0x30 |
Definition at line 386 of file spgist_private.h.
Referenced by spg_desc(), spg_redo(), and spgAddNodeAction().
| #define XLOG_SPGIST_CREATE_INDEX 0x00 |
Definition at line 383 of file spgist_private.h.
Referenced by spg_desc(), spg_redo(), and spgbuild().
| #define XLOG_SPGIST_MOVE_LEAFS 0x20 |
Definition at line 385 of file spgist_private.h.
Referenced by moveLeafs(), spg_desc(), and spg_redo().
| #define XLOG_SPGIST_PICKSPLIT 0x50 |
Definition at line 388 of file spgist_private.h.
Referenced by doPickSplit(), spg_desc(), and spg_redo().
| #define XLOG_SPGIST_SPLIT_TUPLE 0x40 |
Definition at line 387 of file spgist_private.h.
Referenced by spg_desc(), spg_redo(), and spgSplitNodeAction().
| #define XLOG_SPGIST_VACUUM_LEAF 0x60 |
Definition at line 389 of file spgist_private.h.
Referenced by spg_desc(), spg_redo(), and vacuumLeafPage().
| #define XLOG_SPGIST_VACUUM_REDIRECT 0x80 |
Definition at line 391 of file spgist_private.h.
Referenced by spg_desc(), spg_redo(), and vacuumRedirectAndPlaceholder().
| #define XLOG_SPGIST_VACUUM_ROOT 0x70 |
Definition at line 390 of file spgist_private.h.
Referenced by spg_desc(), spg_redo(), and vacuumLeafRoot().
| typedef struct SpGistCache SpGistCache |
| typedef SpGistDeadTupleData* SpGistDeadTuple |
Definition at line 325 of file spgist_private.h.
| typedef struct SpGistDeadTupleData SpGistDeadTupleData |
| typedef SpGistInnerTupleData* SpGistInnerTuple |
Definition at line 219 of file spgist_private.h.
| typedef struct SpGistInnerTupleData SpGistInnerTupleData |
| typedef struct SpGistLastUsedPage SpGistLastUsedPage |
| typedef SpGistLeafTupleData* SpGistLeafTuple |
Definition at line 297 of file spgist_private.h.
| typedef struct SpGistLeafTupleData SpGistLeafTupleData |
| typedef struct SpGistLUPCache SpGistLUPCache |
| typedef struct SpGistMetaPageData SpGistMetaPageData |
| typedef SpGistNodeTupleData* SpGistNodeTuple |
Definition at line 254 of file spgist_private.h.
| typedef IndexTupleData SpGistNodeTupleData |
Definition at line 252 of file spgist_private.h.
| typedef SpGistPageOpaqueData* SpGistPageOpaque |
Definition at line 47 of file spgist_private.h.
| typedef struct SpGistPageOpaqueData SpGistPageOpaqueData |
| typedef SpGistScanOpaqueData* SpGistScanOpaque |
Definition at line 169 of file spgist_private.h.
| typedef struct SpGistScanOpaqueData SpGistScanOpaqueData |
| typedef struct SpGistState SpGistState |
| typedef struct SpGistTypeDesc SpGistTypeDesc |
| typedef struct spgxlogAddLeaf spgxlogAddLeaf |
| typedef struct spgxlogAddNode spgxlogAddNode |
| typedef struct spgxlogMoveLeafs spgxlogMoveLeafs |
| typedef struct spgxlogPickSplit spgxlogPickSplit |
| typedef struct spgxlogSplitTuple spgxlogSplitTuple |
| typedef struct spgxlogState spgxlogState |
| typedef struct spgxlogVacuumLeaf spgxlogVacuumLeaf |
| typedef struct spgxlogVacuumRedirect spgxlogVacuumRedirect |
| typedef struct spgxlogVacuumRoot spgxlogVacuumRoot |
| void initSpGistState | ( | SpGistState * | state, | |
| Relation | index | |||
| ) |
Definition at line 108 of file spgutils.c.
References SpGistCache::attLabelType, SpGistState::attLabelType, SpGistCache::attPrefixType, SpGistState::attPrefixType, SpGistCache::attType, SpGistState::attType, SpGistCache::config, SpGistState::config, SpGistState::deadTupleStorage, GetTopTransactionIdIfAny(), SpGistState::isBuild, SpGistState::myXid, palloc0(), SGDTSIZE, and spgGetCache().
Referenced by spgbeginscan(), spgbuild(), spginsert(), and spgvacuumscan().
{
SpGistCache *cache;
/* Get cached static information about index */
cache = spgGetCache(index);
state->config = cache->config;
state->attType = cache->attType;
state->attPrefixType = cache->attPrefixType;
state->attLabelType = cache->attLabelType;
/* Make workspace for constructing dead tuples */
state->deadTupleStorage = palloc0(SGDTSIZE);
/* Set XID to use in redirection tuples */
state->myXid = GetTopTransactionIdIfAny();
/* Assume we're not in an index build (spgbuild will override) */
state->isBuild = false;
}
| void spgdoinsert | ( | Relation | index, | |
| SpGistState * | state, | |||
| ItemPointer | heapPtr, | |||
| Datum | datum, | |||
| bool | isnull | |||
| ) |
Definition at line 1842 of file spgdoinsert.c.
References addLeafTuple(), spgChooseOut::addNode, SpGistInnerTupleData::allTheSame, spgChooseIn::allTheSame, Assert, SpGistTypeDesc::attlen, SpGistState::attType, SPPageDesc::blkno, SPPageDesc::buffer, BUFFER_LOCK_EXCLUSIVE, BufferGetBlockNumber(), BufferGetPage, CHECK_FOR_INTERRUPTS, checkSplitConditions(), SpGistState::config, spgChooseIn::datum, doPickSplit(), elog, ereport, errcode(), errhint(), errmsg(), ERROR, FunctionCall2Coll(), GBUF_LEAF, GBUF_NULLS, spgChooseIn::hasPrefix, index_getprocinfo(), InvalidBlockNumber, InvalidBuffer, spgChooseIn::leafDatum, spgChooseIn::level, LockBuffer(), spgConfigOut::longValuesOK, spgChooseOut::matchNode, Min, moveLeafs(), SpGistInnerTupleData::nNodes, spgChooseIn::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, spgChooseOut::result, spgChooseOut::resultType, SGDTSIZE, SGITDATUM, SGLTHDRSZ, SpGistLeafTupleData::size, spgAddNode, spgAddNodeAction(), spgExtractNodeLabels(), spgFormLeafTuple(), SPGIST_CHOOSE_PROC, SPGIST_NULL_BLKNO, SPGIST_PAGE_CAPACITY, SpGistGetBuffer(), SpGistGetTypeSize(), SpGistPageGetFreeSpace, SpGistPageIsLeaf, SpGistPageStoresNulls, SpGistSetLastUsedPage(), spgMatchNode, spgMatchNodeAction(), spgSplitNodeAction(), spgSplitTuple, and UnlockReleaseBuffer().
Referenced by spginsert(), and spgistBuildCallback().
{
int level = 0;
Datum leafDatum;
int leafSize;
SPPageDesc current,
parent;
FmgrInfo *procinfo = NULL;
/*
* Look up FmgrInfo of the user-defined choose function once, to save
* cycles in the loop below.
*/
if (!isnull)
procinfo = index_getprocinfo(index, 1, SPGIST_CHOOSE_PROC);
/*
* Since we don't use index_form_tuple in this AM, we have to make sure
* value to be inserted is not toasted; FormIndexDatum doesn't guarantee
* that.
*/
if (!isnull && state->attType.attlen == -1)
datum = PointerGetDatum(PG_DETOAST_DATUM(datum));
leafDatum = datum;
/*
* Compute space needed for a leaf tuple containing the given datum.
*
* If it isn't gonna fit, and the opclass can't reduce the datum size by
* suffixing, bail out now rather than getting into an endless loop.
*/
if (!isnull)
leafSize = SGLTHDRSZ + sizeof(ItemIdData) +
SpGistGetTypeSize(&state->attType, leafDatum);
else
leafSize = SGDTSIZE + sizeof(ItemIdData);
if (leafSize > SPGIST_PAGE_CAPACITY && !state->config.longValuesOK)
ereport(ERROR,
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
errmsg("index row size %lu exceeds maximum %lu for index \"%s\"",
(unsigned long) (leafSize - sizeof(ItemIdData)),
(unsigned long) (SPGIST_PAGE_CAPACITY - sizeof(ItemIdData)),
RelationGetRelationName(index)),
errhint("Values larger than a buffer page cannot be indexed.")));
/* Initialize "current" to the appropriate root page */
current.blkno = isnull ? SPGIST_NULL_BLKNO : SPGIST_ROOT_BLKNO;
current.buffer = InvalidBuffer;
current.page = NULL;
current.offnum = FirstOffsetNumber;
current.node = -1;
/* "parent" is invalid for the moment */
parent.blkno = InvalidBlockNumber;
parent.buffer = InvalidBuffer;
parent.page = NULL;
parent.offnum = InvalidOffsetNumber;
parent.node = -1;
for (;;)
{
bool isNew = false;
/*
* Bail out if query cancel is pending. We must have this somewhere
* in the loop since a broken opclass could produce an infinite
* picksplit loop.
*/
CHECK_FOR_INTERRUPTS();
if (current.blkno == InvalidBlockNumber)
{
/*
* Create a leaf page. If leafSize is too large to fit on a page,
* we won't actually use the page yet, but it simplifies the API
* for doPickSplit to always have a leaf page at hand; so just
* quietly limit our request to a page size.
*/
current.buffer =
SpGistGetBuffer(index,
GBUF_LEAF | (isnull ? GBUF_NULLS : 0),
Min(leafSize, SPGIST_PAGE_CAPACITY),
&isNew);
current.blkno = BufferGetBlockNumber(current.buffer);
}
else if (parent.buffer == InvalidBuffer ||
current.blkno != parent.blkno)
{
current.buffer = ReadBuffer(index, current.blkno);
LockBuffer(current.buffer, BUFFER_LOCK_EXCLUSIVE);
}
else
{
/* inner tuple can be stored on the same page as parent one */
current.buffer = parent.buffer;
}
current.page = BufferGetPage(current.buffer);
/* should not arrive at a page of the wrong type */
if (isnull ? !SpGistPageStoresNulls(current.page) :
SpGistPageStoresNulls(current.page))
elog(ERROR, "SPGiST index page %u has wrong nulls flag",
current.blkno);
if (SpGistPageIsLeaf(current.page))
{
SpGistLeafTuple leafTuple;
int nToSplit,
sizeToSplit;
leafTuple = spgFormLeafTuple(state, heapPtr, leafDatum, isnull);
if (leafTuple->size + sizeof(ItemIdData) <=
SpGistPageGetFreeSpace(current.page, 1))
{
/* it fits on page, so insert it and we're done */
addLeafTuple(index, state, leafTuple,
¤t, &parent, isnull, isNew);
break;
}
else if ((sizeToSplit =
checkSplitConditions(index, state, ¤t,
&nToSplit)) < SPGIST_PAGE_CAPACITY / 2 &&
nToSplit < 64 &&
leafTuple->size + sizeof(ItemIdData) + sizeToSplit <= SPGIST_PAGE_CAPACITY)
{
/*
* the amount of data is pretty small, so just move the whole
* chain to another leaf page rather than splitting it.
*/
Assert(!isNew);
moveLeafs(index, state, ¤t, &parent, leafTuple, isnull);
break; /* we're done */
}
else
{
/* picksplit */
if (doPickSplit(index, state, ¤t, &parent,
leafTuple, level, isnull, isNew))
break; /* doPickSplit installed new tuples */
/* leaf tuple will not be inserted yet */
pfree(leafTuple);
/*
* current now describes new inner tuple, go insert into it
*/
Assert(!SpGistPageIsLeaf(current.page));
goto process_inner_tuple;
}
}
else /* non-leaf page */
{
/*
* Apply the opclass choose function to figure out how to insert
* the given datum into the current inner tuple.
*/
SpGistInnerTuple innerTuple;
spgChooseIn in;
spgChooseOut out;
/*
* spgAddNode and spgSplitTuple cases will loop back to here to
* complete the insertion operation. Just in case the choose
* function is broken and produces add or split requests
* repeatedly, check for query cancel.
*/
process_inner_tuple:
CHECK_FOR_INTERRUPTS();
innerTuple = (SpGistInnerTuple) PageGetItem(current.page,
PageGetItemId(current.page, current.offnum));
in.datum = datum;
in.leafDatum = leafDatum;
in.level = level;
in.allTheSame = innerTuple->allTheSame;
in.hasPrefix = (innerTuple->prefixSize > 0);
in.prefixDatum = SGITDATUM(innerTuple, state);
in.nNodes = innerTuple->nNodes;
in.nodeLabels = spgExtractNodeLabels(state, innerTuple);
memset(&out, 0, sizeof(out));
if (!isnull)
{
/* use user-defined choose method */
FunctionCall2Coll(procinfo,
index->rd_indcollation[0],
PointerGetDatum(&in),
PointerGetDatum(&out));
}
else
{
/* force "match" action (to insert to random subnode) */
out.resultType = spgMatchNode;
}
if (innerTuple->allTheSame)
{
/*
* It's not allowed to do an AddNode at an allTheSame tuple.
* Opclass must say "match", in which case we choose a random
* one of the nodes to descend into, or "split".
*/
if (out.resultType == spgAddNode)
elog(ERROR, "cannot add a node to an allTheSame inner tuple");
else if (out.resultType == spgMatchNode)
out.result.matchNode.nodeN = random() % innerTuple->nNodes;
}
switch (out.resultType)
{
case spgMatchNode:
/* Descend to N'th child node */
spgMatchNodeAction(index, state, innerTuple,
¤t, &parent,
out.result.matchNode.nodeN);
/* Adjust level as per opclass request */
level += out.result.matchNode.levelAdd;
/* Replace leafDatum and recompute leafSize */
if (!isnull)
{
leafDatum = out.result.matchNode.restDatum;
leafSize = SGLTHDRSZ + sizeof(ItemIdData) +
SpGistGetTypeSize(&state->attType, leafDatum);
}
/*
* Loop around and attempt to insert the new leafDatum at
* "current" (which might reference an existing child
* tuple, or might be invalid to force us to find a new
* page for the tuple).
*
* Note: if the opclass sets longValuesOK, we rely on the
* choose function to eventually shorten the leafDatum
* enough to fit on a page. We could add a test here to
* complain if the datum doesn't get visibly shorter each
* time, but that could get in the way of opclasses that
* "simplify" datums in a way that doesn't necessarily
* lead to physical shortening on every cycle.
*/
break;
case spgAddNode:
/* AddNode is not sensible if nodes don't have labels */
if (in.nodeLabels == NULL)
elog(ERROR, "cannot add a node to an inner tuple without node labels");
/* Add node to inner tuple, per request */
spgAddNodeAction(index, state, innerTuple,
¤t, &parent,
out.result.addNode.nodeN,
out.result.addNode.nodeLabel);
/*
* Retry insertion into the enlarged node. We assume that
* we'll get a MatchNode result this time.
*/
goto process_inner_tuple;
break;
case spgSplitTuple:
/* Split inner tuple, per request */
spgSplitNodeAction(index, state, innerTuple,
¤t, &out);
/* Retry insertion into the split node */
goto process_inner_tuple;
break;
default:
elog(ERROR, "unrecognized SPGiST choose result: %d",
(int) out.resultType);
break;
}
}
} /* end loop */
/*
* Release any buffers we're still holding. Beware of possibility that
* current and parent reference same buffer.
*/
if (current.buffer != InvalidBuffer)
{
SpGistSetLastUsedPage(index, current.buffer);
UnlockReleaseBuffer(current.buffer);
}
if (parent.buffer != InvalidBuffer &&
parent.buffer != current.buffer)
{
SpGistSetLastUsedPage(index, parent.buffer);
UnlockReleaseBuffer(parent.buffer);
}
}
| Datum* spgExtractNodeLabels | ( | SpGistState * | state, | |
| SpGistInnerTuple | innerTuple | |||
| ) |
Definition at line 743 of file spgutils.c.
References elog, ERROR, i, IndexTupleHasNulls, SpGistInnerTupleData::nNodes, palloc(), SGITITERATE, SGITNODEPTR, and SGNTDATUM.
Referenced by spgdoinsert(), and spgWalk().
{
Datum *nodeLabels;
int i;
SpGistNodeTuple node;
/* Either all the labels must be NULL, or none. */
node = SGITNODEPTR(innerTuple);
if (IndexTupleHasNulls(node))
{
SGITITERATE(innerTuple, i, node)
{
if (!IndexTupleHasNulls(node))
elog(ERROR, "some but not all node labels are null in SPGiST inner tuple");
}
/* They're all null, so just return NULL */
return NULL;
}
else
{
nodeLabels = (Datum *) palloc(sizeof(Datum) * innerTuple->nNodes);
SGITITERATE(innerTuple, i, node)
{
if (IndexTupleHasNulls(node))
elog(ERROR, "some but not all node labels are null in SPGiST inner tuple");
nodeLabels[i] = SGNTDATUM(node, state);
}
return nodeLabels;
}
}
| SpGistDeadTuple spgFormDeadTuple | ( | SpGistState * | state, | |
| int | tupstate, | |||
| BlockNumber | blkno, | |||
| OffsetNumber | offnum | |||
| ) |
Definition at line 713 of file spgutils.c.
References Assert, SpGistState::deadTupleStorage, InvalidOffsetNumber, 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().
{
SpGistDeadTuple tuple = (SpGistDeadTuple) state->deadTupleStorage;
tuple->tupstate = tupstate;
tuple->size = SGDTSIZE;
tuple->nextOffset = InvalidOffsetNumber;
if (tupstate == SPGIST_REDIRECT)
{
ItemPointerSet(&tuple->pointer, blkno, offnum);
Assert(TransactionIdIsValid(state->myXid));
tuple->xid = state->myXid;
}
else
{
ItemPointerSetInvalid(&tuple->pointer);
tuple->xid = InvalidTransactionId;
}
return tuple;
}
| SpGistInnerTuple spgFormInnerTuple | ( | SpGistState * | state, | |
| bool | hasPrefix, | |||
| Datum | prefix, | |||
| int | nNodes, | |||
| SpGistNodeTuple * | nodes | |||
| ) |
Definition at line 630 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().
{
SpGistInnerTuple tup;
unsigned int size;
unsigned int prefixSize;
int i;
char *ptr;
/* Compute size needed */
if (hasPrefix)
prefixSize = SpGistGetTypeSize(&state->attPrefixType, prefix);
else
prefixSize = 0;
size = SGITHDRSZ + prefixSize;
/* Note: we rely on node tuple sizes to be maxaligned already */
for (i = 0; i < nNodes; i++)
size += IndexTupleSize(nodes[i]);
/*
* Ensure that we can replace the tuple with a dead tuple later. This
* test is unnecessary given current tuple layouts, but let's be safe.
*/
if (size < SGDTSIZE)
size = SGDTSIZE;
/*
* Inner tuple should be small enough to fit on a page
*/
if (size > SPGIST_PAGE_CAPACITY - sizeof(ItemIdData))
ereport(ERROR,
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
errmsg("SP-GiST inner tuple size %lu exceeds maximum %lu",
(unsigned long) size,
(unsigned long) (SPGIST_PAGE_CAPACITY - sizeof(ItemIdData))),
errhint("Values larger than a buffer page cannot be indexed.")));
/*
* Check for overflow of header fields --- probably can't fail if the
* above succeeded, but let's be paranoid
*/
if (size > SGITMAXSIZE ||
prefixSize > SGITMAXPREFIXSIZE ||
nNodes > SGITMAXNNODES)
elog(ERROR, "SPGiST inner tuple header field is too small");
/* OK, form the tuple */
tup = (SpGistInnerTuple) palloc0(size);
tup->nNodes = nNodes;
tup->prefixSize = prefixSize;
tup->size = size;
if (hasPrefix)
memcpyDatum(SGITDATAPTR(tup), &state->attPrefixType, prefix);
ptr = (char *) SGITNODEPTR(tup);
for (i = 0; i < nNodes; i++)
{
SpGistNodeTuple node = nodes[i];
memcpy(ptr, node, IndexTupleSize(node));
ptr += IndexTupleSize(node);
}
return tup;
}
| SpGistLeafTuple spgFormLeafTuple | ( | SpGistState * | state, | |
| ItemPointer | heapPtr, | |||
| Datum | datum, | |||
| bool | isnull | |||
| ) |
Definition at line 550 of file spgutils.c.
References SpGistState::attType, SpGistLeafTupleData::heapPtr, memcpyDatum(), SpGistLeafTupleData::nextOffset, palloc0(), SGDTSIZE, SGLTDATAPTR, SpGistLeafTupleData::size, and SpGistGetTypeSize().
Referenced by doPickSplit(), and spgdoinsert().
{
SpGistLeafTuple tup;
unsigned int size;
/* compute space needed (note result is already maxaligned) */
size = SGLTHDRSZ;
if (!isnull)
size += SpGistGetTypeSize(&state->attType, datum);
/*
* Ensure that we can replace the tuple with a dead tuple later. This
* test is unnecessary when !isnull, but let's be safe.
*/
if (size < SGDTSIZE)
size = SGDTSIZE;
/* OK, form the tuple */
tup = (SpGistLeafTuple) palloc0(size);
tup->size = size;
tup->nextOffset = InvalidOffsetNumber;
tup->heapPtr = *heapPtr;
if (!isnull)
memcpyDatum(SGLTDATAPTR(tup), &state->attType, datum);
return tup;
}
| SpGistNodeTuple spgFormNodeTuple | ( | SpGistState * | state, | |
| Datum | label, | |||
| bool | isnull | |||
| ) |
Definition at line 587 of file spgutils.c.
References SpGistState::attLabelType, ereport, errcode(), errmsg(), ERROR, INDEX_SIZE_MASK, ItemPointerSetInvalid, memcpyDatum(), palloc0(), SGNTDATAPTR, SpGistGetTypeSize(), IndexTupleData::t_info, and IndexTupleData::t_tid.
Referenced by addNode(), doPickSplit(), and spgSplitNodeAction().
{
SpGistNodeTuple tup;
unsigned int size;
unsigned short infomask = 0;
/* compute space needed (note result is already maxaligned) */
size = SGNTHDRSZ;
if (!isnull)
size += SpGistGetTypeSize(&state->attLabelType, label);
/*
* Here we make sure that the size will fit in the field reserved for it
* in t_info.
*/
if ((size & INDEX_SIZE_MASK) != size)
ereport(ERROR,
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
errmsg("index row requires %lu bytes, maximum size is %lu",
(unsigned long) size,
(unsigned long) INDEX_SIZE_MASK)));
tup = (SpGistNodeTuple) palloc0(size);
if (isnull)
infomask |= INDEX_NULL_MASK;
/* we don't bother setting the INDEX_VAR_MASK bit */
infomask |= size;
tup->t_info = infomask;
/* The TID field will be filled in later */
ItemPointerSetInvalid(&tup->t_tid);
if (!isnull)
memcpyDatum(SGNTDATAPTR(tup), &state->attLabelType, label);
return tup;
}
| SpGistCache* spgGetCache | ( | Relation | index | ) |
Definition at line 42 of file spgutils.c.
References Assert, SpGistCache::attLabelType, SpGistCache::attPrefixType, tupleDesc::attrs, SpGistCache::attType, spgConfigIn::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().
{
SpGistCache *cache;
if (index->rd_amcache == NULL)
{
Oid atttype;
spgConfigIn in;
FmgrInfo *procinfo;
Buffer metabuffer;
SpGistMetaPageData *metadata;
cache = MemoryContextAllocZero(index->rd_indexcxt,
sizeof(SpGistCache));
/* SPGiST doesn't support multi-column indexes */
Assert(index->rd_att->natts == 1);
/*
* Get the actual data type of the indexed column from the index
* tupdesc. We pass this to the opclass config function so that
* polymorphic opclasses are possible.
*/
atttype = index->rd_att->attrs[0]->atttypid;
/* Call the config function to get config info for the opclass */
in.attType = atttype;
procinfo = index_getprocinfo(index, 1, SPGIST_CONFIG_PROC);
FunctionCall2Coll(procinfo,
index->rd_indcollation[0],
PointerGetDatum(&in),
PointerGetDatum(&cache->config));
/* Get the information we need about each relevant datatype */
fillTypeDesc(&cache->attType, atttype);
fillTypeDesc(&cache->attPrefixType, cache->config.prefixType);
fillTypeDesc(&cache->attLabelType, cache->config.labelType);
/* Last, get the lastUsedPages data from the metapage */
metabuffer = ReadBuffer(index, SPGIST_METAPAGE_BLKNO);
LockBuffer(metabuffer, BUFFER_LOCK_SHARE);
metadata = SpGistPageGetMeta(BufferGetPage(metabuffer));
if (metadata->magicNumber != SPGIST_MAGIC_NUMBER)
elog(ERROR, "index \"%s\" is not an SP-GiST index",
RelationGetRelationName(index));
cache->lastUsedPages = metadata->lastUsedPages;
UnlockReleaseBuffer(metabuffer);
index->rd_amcache = (void *) cache;
}
else
{
/* assume it's up to date */
cache = (SpGistCache *) index->rd_amcache;
}
return cache;
}
Definition at line 309 of file spgutils.c.
References allocNewBuffer(), Assert, SpGistLastUsedPage::blkno, 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_PAGE_CAPACITY, SpGistBlockIsFixed, SpGistInitBuffer(), SpGistPageIsDeleted, SpGistPageIsLeaf, SpGistPageStoresNulls, and UnlockReleaseBuffer().
Referenced by doPickSplit(), moveLeafs(), spgAddNodeAction(), spgdoinsert(), and spgSplitNodeAction().
{
SpGistCache *cache = spgGetCache(index);
SpGistLastUsedPage *lup;
/* Bail out if even an empty page wouldn't meet the demand */
if (needSpace > SPGIST_PAGE_CAPACITY)
elog(ERROR, "desired SPGiST tuple size is too big");
/*
* If possible, increase the space request to include relation's
* fillfactor. This ensures that when we add unrelated tuples to a page,
* we try to keep 100-fillfactor% available for adding tuples that are
* related to the ones already on it. But fillfactor mustn't cause an
* error for requests that would otherwise be legal.
*/
needSpace += RelationGetTargetPageFreeSpace(index,
SPGIST_DEFAULT_FILLFACTOR);
needSpace = Min(needSpace, SPGIST_PAGE_CAPACITY);
/* Get the cache entry for this flags setting */
lup = GET_LUP(cache, flags);
/* If we have nothing cached, just turn it over to allocNewBuffer */
if (lup->blkno == InvalidBlockNumber)
{
*isNew = true;
return allocNewBuffer(index, flags);
}
/* fixed pages should never be in cache */
Assert(!SpGistBlockIsFixed(lup->blkno));
/* If cached freeSpace isn't enough, don't bother looking at the page */
if (lup->freeSpace >= needSpace)
{
Buffer buffer;
Page page;
buffer = ReadBuffer(index, lup->blkno);
if (!ConditionalLockBuffer(buffer))
{
/*
* buffer is locked by another process, so return a new buffer
*/
ReleaseBuffer(buffer);
*isNew = true;
return allocNewBuffer(index, flags);
}
page = BufferGetPage(buffer);
if (PageIsNew(page) || SpGistPageIsDeleted(page) || PageIsEmpty(page))
{
/* OK to initialize the page */
uint16 pageflags = 0;
if (GBUF_REQ_LEAF(flags))
pageflags |= SPGIST_LEAF;
if (GBUF_REQ_NULLS(flags))
pageflags |= SPGIST_NULLS;
SpGistInitBuffer(buffer, pageflags);
lup->freeSpace = PageGetExactFreeSpace(page) - needSpace;
*isNew = true;
return buffer;
}
/*
* Check that page is of right type and has enough space. We must
* recheck this since our cache isn't necessarily up to date.
*/
if ((GBUF_REQ_LEAF(flags) ? SpGistPageIsLeaf(page) : !SpGistPageIsLeaf(page)) &&
(GBUF_REQ_NULLS(flags) ? SpGistPageStoresNulls(page) : !SpGistPageStoresNulls(page)))
{
int freeSpace = PageGetExactFreeSpace(page);
if (freeSpace >= needSpace)
{
/* Success, update freespace info and return the buffer */
lup->freeSpace = freeSpace - needSpace;
*isNew = false;
return buffer;
}
}
/*
* fallback to allocation of new buffer
*/
UnlockReleaseBuffer(buffer);
}
/* No success with cache, so return a new buffer */
*isNew = true;
return allocNewBuffer(index, flags);
}
| unsigned int SpGistGetTypeSize | ( | SpGistTypeDesc * | att, | |
| Datum | datum | |||
| ) |
Definition at line 513 of file spgutils.c.
References SpGistTypeDesc::attbyval, SpGistTypeDesc::attlen, MAXALIGN, and VARSIZE_ANY.
Referenced by spgdoinsert(), spgFormInnerTuple(), spgFormLeafTuple(), and spgFormNodeTuple().
{
unsigned int size;
if (att->attbyval)
size = sizeof(Datum);
else if (att->attlen > 0)
size = att->attlen;
else
size = VARSIZE_ANY(datum);
return MAXALIGN(size);
}
Definition at line 464 of file spgutils.c.
References Assert, BufferGetPage, BufferGetPageSize, and SpGistInitPage().
Referenced by allocNewBuffer(), doPickSplit(), spgbuild(), SpGistGetBuffer(), spgRedoAddLeaf(), spgRedoAddNode(), spgRedoCreateIndex(), spgRedoMoveLeafs(), spgRedoPickSplit(), spgRedoSplitTuple(), and spgvacuumpage().
{
Assert(BufferGetPageSize(b) == BLCKSZ);
SpGistInitPage(BufferGetPage(b), f);
}
| void SpGistInitMetapage | ( | Page | page | ) |
Definition at line 474 of file spgutils.c.
References SpGistLastUsedPage::blkno, SpGistLUPCache::cachedPage, i, InvalidBlockNumber, SpGistMetaPageData::lastUsedPages, SpGistMetaPageData::magicNumber, SPGIST_META, SpGistInitPage(), and SpGistPageGetMeta.
Referenced by spgbuild(), spgbuildempty(), and spgRedoCreateIndex().
{
SpGistMetaPageData *metadata;
int i;
SpGistInitPage(page, SPGIST_META);
metadata = SpGistPageGetMeta(page);
memset(metadata, 0, sizeof(SpGistMetaPageData));
metadata->magicNumber = SPGIST_MAGIC_NUMBER;
/* initialize last-used-page cache to empty */
for (i = 0; i < SPGIST_CACHED_PAGES; i++)
metadata->lastUsedPages.cachedPage[i].blkno = InvalidBlockNumber;
}
Definition at line 449 of file spgutils.c.
References SpGistPageOpaqueData::flags, MAXALIGN, PageInit(), SpGistPageOpaqueData::spgist_page_id, and SpGistPageGetOpaque.
Referenced by spgbuildempty(), SpGistInitBuffer(), and SpGistInitMetapage().
{
SpGistPageOpaque opaque;
PageInit(page, BLCKSZ, MAXALIGN(sizeof(SpGistPageOpaqueData)));
opaque = SpGistPageGetOpaque(page);
memset(opaque, 0, sizeof(SpGistPageOpaqueData));
opaque->flags = f;
opaque->spgist_page_id = SPGIST_PAGE_ID;
}
Definition at line 137 of file spgutils.c.
References 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().
{
Buffer buffer;
bool needLock;
/* First, try to get a page from FSM */
for (;;)
{
BlockNumber blkno = GetFreeIndexPage(index);
if (blkno == InvalidBlockNumber)
break; /* nothing known to FSM */
/*
* The fixed pages shouldn't ever be listed in FSM, but just in case
* one is, ignore it.
*/
if (SpGistBlockIsFixed(blkno))
continue;
buffer = ReadBuffer(index, blkno);
/*
* We have to guard against the possibility that someone else already
* recycled this page; the buffer may be locked if so.
*/
if (ConditionalLockBuffer(buffer))
{
Page page = BufferGetPage(buffer);
if (PageIsNew(page))
return buffer; /* OK to use, if never initialized */
if (SpGistPageIsDeleted(page) || PageIsEmpty(page))
return buffer; /* OK to use */
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
}
/* Can't use it, so release buffer and try again */
ReleaseBuffer(buffer);
}
/* Must extend the file */
needLock = !RELATION_IS_LOCAL(index);
if (needLock)
LockRelationForExtension(index, ExclusiveLock);
buffer = ReadBuffer(index, P_NEW);
LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
if (needLock)
UnlockRelationForExtension(index, ExclusiveLock);
return buffer;
}
| OffsetNumber SpGistPageAddNewItem | ( | SpGistState * | state, | |
| Page | page, | |||
| Item | item, | |||
| Size | size, | |||
| OffsetNumber * | startOffset, | |||
| bool | errorOK | |||
| ) |
Definition at line 786 of file spgutils.c.
References Assert, elog, ERROR, 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().
{
SpGistPageOpaque opaque = SpGistPageGetOpaque(page);
OffsetNumber i,
maxoff,
offnum;
if (opaque->nPlaceholder > 0 &&
PageGetExactFreeSpace(page) + SGDTSIZE >= MAXALIGN(size))
{
/* Try to replace a placeholder */
maxoff = PageGetMaxOffsetNumber(page);
offnum = InvalidOffsetNumber;
for (;;)
{
if (startOffset && *startOffset != InvalidOffsetNumber)
i = *startOffset;
else
i = FirstOffsetNumber;
for (; i <= maxoff; i++)
{
SpGistDeadTuple it = (SpGistDeadTuple) PageGetItem(page,
PageGetItemId(page, i));
if (it->tupstate == SPGIST_PLACEHOLDER)
{
offnum = i;
break;
}
}
/* Done if we found a placeholder */
if (offnum != InvalidOffsetNumber)
break;
if (startOffset && *startOffset != InvalidOffsetNumber)
{
/* Hint was no good, re-search from beginning */
*startOffset = InvalidOffsetNumber;
continue;
}
/* Hmm, no placeholder found? */
opaque->nPlaceholder = 0;
break;
}
if (offnum != InvalidOffsetNumber)
{
/* Replace the placeholder tuple */
PageIndexTupleDelete(page, offnum);
offnum = PageAddItem(page, item, size, offnum, false, false);
/*
* We should not have failed given the size check at the top of
* the function, but test anyway. If we did fail, we must PANIC
* because we've already deleted the placeholder tuple, and
* there's no other way to keep the damage from getting to disk.
*/
if (offnum != InvalidOffsetNumber)
{
Assert(opaque->nPlaceholder > 0);
opaque->nPlaceholder--;
if (startOffset)
*startOffset = offnum + 1;
}
else
elog(PANIC, "failed to add item of size %u to SPGiST index page",
(int) size);
return offnum;
}
}
/* No luck in replacing a placeholder, so just add it to the page */
offnum = PageAddItem(page, item, size,
InvalidOffsetNumber, false, false);
if (offnum == InvalidOffsetNumber && !errorOK)
elog(ERROR, "failed to add item of size %u to SPGiST index page",
(int) size);
return offnum;
}
Definition at line 414 of file spgutils.c.
References SpGistLastUsedPage::blkno, BufferGetBlockNumber(), BufferGetPage, SpGistLastUsedPage::freeSpace, GBUF_INNER_PARITY, GET_LUP, InvalidBlockNumber, PageGetExactFreeSpace(), spgGetCache(), SpGistBlockIsFixed, SpGistPageIsLeaf, and SpGistPageStoresNulls.
Referenced by doPickSplit(), moveLeafs(), spgAddNodeAction(), spgdoinsert(), spgMatchNodeAction(), spgprocesspending(), spgSplitNodeAction(), and spgvacuumpage().
{
SpGistCache *cache = spgGetCache(index);
SpGistLastUsedPage *lup;
int freeSpace;
Page page = BufferGetPage(buffer);
BlockNumber blkno = BufferGetBlockNumber(buffer);
int flags;
/* Never enter fixed pages (root pages) in cache, though */
if (SpGistBlockIsFixed(blkno))
return;
if (SpGistPageIsLeaf(page))
flags = GBUF_LEAF;
else
flags = GBUF_INNER_PARITY(blkno);
if (SpGistPageStoresNulls(page))
flags |= GBUF_NULLS;
lup = GET_LUP(cache, flags);
freeSpace = PageGetExactFreeSpace(page);
if (lup->blkno == InvalidBlockNumber || lup->blkno == blkno ||
lup->freeSpace < freeSpace)
{
lup->blkno = blkno;
lup->freeSpace = freeSpace;
}
}
| void SpGistUpdateMetaPage | ( | Relation | index | ) |
Definition at line 202 of file spgutils.c.
References BufferGetPage, ConditionalLockBuffer(), SpGistCache::lastUsedPages, SpGistMetaPageData::lastUsedPages, MarkBufferDirty(), NULL, RelationData::rd_amcache, ReadBuffer(), ReleaseBuffer(), SPGIST_METAPAGE_BLKNO, SpGistPageGetMeta, and UnlockReleaseBuffer().
Referenced by spgbuild(), spginsert(), and spgvacuumscan().
{
SpGistCache *cache = (SpGistCache *) index->rd_amcache;
if (cache != NULL)
{
Buffer metabuffer;
SpGistMetaPageData *metadata;
metabuffer = ReadBuffer(index, SPGIST_METAPAGE_BLKNO);
if (ConditionalLockBuffer(metabuffer))
{
metadata = SpGistPageGetMeta(BufferGetPage(metabuffer));
metadata->lastUsedPages = cache->lastUsedPages;
MarkBufferDirty(metabuffer);
UnlockReleaseBuffer(metabuffer);
}
else
{
ReleaseBuffer(metabuffer);
}
}
}
| void spgPageIndexMultiDelete | ( | SpGistState * | state, | |
| Page | page, | |||
| OffsetNumber * | itemnos, | |||
| int | nitems, | |||
| int | firststate, | |||
| int | reststate, | |||
| BlockNumber | blkno, | |||
| OffsetNumber | offnum | |||
| ) |
Definition at line 128 of file spgdoinsert.c.
References cmpOffsetNumbers(), elog, ERROR, i, NULL, PageAddItem(), PageIndexMultiDelete(), palloc(), pfree(), qsort, SpGistDeadTupleData::size, spgFormDeadTuple(), SPGIST_PLACEHOLDER, SPGIST_REDIRECT, SpGistPageGetOpaque, and SpGistDeadTupleData::tupstate.
Referenced by doPickSplit(), moveLeafs(), spgRedoMoveLeafs(), spgRedoPickSplit(), spgRedoVacuumLeaf(), and vacuumLeafPage().
{
OffsetNumber firstItem;
OffsetNumber *sortednos;
SpGistDeadTuple tuple = NULL;
int i;
if (nitems == 0)
return; /* nothing to do */
/*
* For efficiency we want to use PageIndexMultiDelete, which requires the
* targets to be listed in sorted order, so we have to sort the itemnos
* array. (This also greatly simplifies the math for reinserting the
* replacement tuples.) However, we must not scribble on the caller's
* array, so we have to make a copy.
*/
sortednos = (OffsetNumber *) palloc(sizeof(OffsetNumber) * nitems);
memcpy(sortednos, itemnos, sizeof(OffsetNumber) * nitems);
if (nitems > 1)
qsort(sortednos, nitems, sizeof(OffsetNumber), cmpOffsetNumbers);
PageIndexMultiDelete(page, sortednos, nitems);
firstItem = itemnos[0];
for (i = 0; i < nitems; i++)
{
OffsetNumber itemno = sortednos[i];
int tupstate;
tupstate = (itemno == firstItem) ? firststate : reststate;
if (tuple == NULL || tuple->tupstate != tupstate)
tuple = spgFormDeadTuple(state, tupstate, blkno, offnum);
if (PageAddItem(page, (Item) tuple, tuple->size,
itemno, false, false) != itemno)
elog(ERROR, "failed to add item of size %u to SPGiST index page",
tuple->size);
if (tupstate == SPGIST_REDIRECT)
SpGistPageGetOpaque(page)->nRedirection++;
else if (tupstate == SPGIST_PLACEHOLDER)
SpGistPageGetOpaque(page)->nPlaceholder++;
}
pfree(sortednos);
}
| void spgUpdateNodeLink | ( | SpGistInnerTuple | tup, | |
| int | nodeN, | |||
| BlockNumber | blkno, | |||
| OffsetNumber | offset | |||
| ) |
Definition at line 48 of file spgdoinsert.c.
References elog, ERROR, i, ItemPointerSet, SGITITERATE, and IndexTupleData::t_tid.
Referenced by saveNodeLink(), spgRedoAddLeaf(), spgRedoAddNode(), spgRedoMoveLeafs(), spgRedoPickSplit(), and spgSplitNodeAction().
{
int i;
SpGistNodeTuple node;
SGITITERATE(tup, i, node)
{
if (i == nodeN)
{
ItemPointerSet(&node->t_tid, blkno, offset);
return;
}
}
elog(ERROR, "failed to find requested node %d in SPGiST inner tuple",
nodeN);
}
1.7.1