/* *SPPageDesctracksallinfoaboutapageweareinsertinginto.Insome *situationsitactuallyidentifiesatuple,orevenaspecificnodewithin *aninnertuple.Butanyofthefieldscanbeinvalid.Ifthebuffer *fieldisvalid,itimpliesweholdpinandexclusivelockonthatbuffer. *pagepointershouldbevalidexactlywhenbufferis.
*/ typedefstruct SPPageDesc
{
BlockNumber blkno; /* block number, or InvalidBlockNumber */
Buffer buffer; /* page's buffer number, or InvalidBuffer */
Page page; /* pointer to page buffer, or NULL */
OffsetNumber offnum; /* offset of tuple, or InvalidOffsetNumber */ int node; /* node number within inner tuple, or -1 */
} SPPageDesc;
/* *SettheitempointerinthenodeN'thentryininnertupletup.This *isusedtoupdatetheparentinnertuple'sdownlinkafteramoveor *splitoperation.
*/ void
spgUpdateNodeLink(SpGistInnerTuple tup, int nodeN,
BlockNumber blkno, OffsetNumber offset)
{ 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);
}
/* *Formanewinnertuplecontainingonemorenodethanthegivenone,with *thespecifiedlabeldatum,insertedatoffset"offset"inthenodearray. *Thenewtuple'sprefixisthesameastheoldone's. * *Notethatthenewnodeinitiallyhasaninvaliddownlink.We'llfinda *pagetopointittolater.
*/ static SpGistInnerTuple
addNode(SpGistState *state, SpGistInnerTuple tuple, Datum label, int offset)
{
SpGistNodeTuple node,
*nodes; int i;
/* if offset is negative, insert at end */ if (offset < 0)
offset = tuple->nNodes; elseif (offset > tuple->nNodes)
elog(ERROR, "invalid offset for adding node to SPGiST inner tuple");
nodes = palloc(sizeof(SpGistNodeTuple) * (tuple->nNodes + 1));
SGITITERATE(tuple, i, node)
{ if (i < offset)
nodes[i] = node; else
nodes[i + 1] = node;
}
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);
/* these will be filled below as needed */
xlrec.offnumLeaf = InvalidOffsetNumber;
xlrec.offnumHeadLeaf = InvalidOffsetNumber;
xlrec.offnumParent = InvalidOffsetNumber;
xlrec.nodeI = 0;
START_CRIT_SECTION();
if (current->offnum == InvalidOffsetNumber ||
SpGistBlockIsRoot(current->blkno))
{ /* Tuple is not part of a chain */
SGLT_SET_NEXTOFFSET(leafTuple, InvalidOffsetNumber);
current->offnum = SpGistPageAddNewItem(state, current->page,
(Item) leafTuple, leafTuple->size,
NULL, false);
xlrec.offnumLeaf = current->offnum;
/* Must update parent's downlink if any */ if (parent->buffer != InvalidBuffer)
{
xlrec.offnumParent = parent->offnum;
xlrec.nodeI = parent->node;
/* update parent only if we actually changed it */ if (xlrec.offnumParent != InvalidOffsetNumber)
{
PageSetLSN(parent->page, recptr);
}
}
END_CRIT_SECTION();
}
/* *Countthenumberandtotalsizeofleaftuplesinthechainstartingat *current->offnum.Returnnumberinto*nToSplitandtotalsizeasfunction *result. * *Klugyspecialcasewhenconsideringtherootpage(i.e.,rootisaleaf *page,butwe'reabouttosplitforthefirsttime):returnfakelarge *valuestoforcespgdoinsert()totakethedoPickSplitratherthan *moveLeafscodepath.moveLeafsisnotpreparedtodealwithrootpage.
*/ staticint
checkSplitConditions(Relation index, SpGistState *state,
SPPageDesc *current, int *nToSplit)
{ int i,
n = 0,
totalSize = 0;
if (SpGistBlockIsRoot(current->blkno))
{ /* return impossible values to force split */
*nToSplit = BLCKSZ; return BLCKSZ;
}
i = current->offnum; while (i != InvalidOffsetNumber)
{
SpGistLeafTuple it;
Assert(i >= FirstOffsetNumber &&
i <= PageGetMaxOffsetNumber(current->page));
it = (SpGistLeafTuple) PageGetItem(current->page,
PageGetItemId(current->page, i)); if (it->tupstate == SPGIST_LIVE)
{
n++;
totalSize += it->size + sizeof(ItemIdData);
} elseif (it->tupstate == SPGIST_DEAD)
{ /* We could see a DEAD tuple as first/only chain item */
Assert(i == current->offnum);
Assert(SGLT_GET_NEXTOFFSET(it) == InvalidOffsetNumber); /* Don't count it in result, because it won't go to other page */
} else
elog(ERROR, "unexpected SPGiST tuple state: %d", it->tupstate);
/* This doesn't work on root page */
Assert(parent->buffer != InvalidBuffer);
Assert(parent->buffer != current->buffer);
/* Locate the tuples to be moved, and count up the space needed */
i = PageGetMaxOffsetNumber(current->page);
toDelete = (OffsetNumber *) palloc(sizeof(OffsetNumber) * i);
toInsert = (OffsetNumber *) palloc(sizeof(OffsetNumber) * (i + 1));
size = newLeafTuple->size + sizeof(ItemIdData);
nDelete = 0;
i = current->offnum; while (i != InvalidOffsetNumber)
{
SpGistLeafTuple it;
Assert(i >= FirstOffsetNumber &&
i <= PageGetMaxOffsetNumber(current->page));
it = (SpGistLeafTuple) PageGetItem(current->page,
PageGetItemId(current->page, i));
if (it->tupstate == SPGIST_LIVE)
{
toDelete[nDelete] = i;
size += it->size + sizeof(ItemIdData);
nDelete++;
} elseif (it->tupstate == SPGIST_DEAD)
{ /* We could see a DEAD tuple as first/only chain item */
Assert(i == current->offnum);
Assert(SGLT_GET_NEXTOFFSET(it) == InvalidOffsetNumber); /* We don't want to move it, so don't count it in size */
toDelete[nDelete] = i;
nDelete++;
replaceDead = true;
} else
elog(ERROR, "unexpected SPGiST tuple state: %d", it->tupstate);
i = SGLT_GET_NEXTOFFSET(it);
}
/* Find a leaf page that will hold them */
nbuf = SpGistGetBuffer(index, GBUF_LEAF | (isNulls ? GBUF_NULLS : 0),
size, &xlrec.newPage);
npage = BufferGetPage(nbuf);
nblkno = BufferGetBlockNumber(nbuf);
Assert(nblkno != current->blkno);
leafdata = leafptr = palloc(size);
START_CRIT_SECTION();
/* copy all the old tuples to new page, unless they're dead */
nInsert = 0; if (!replaceDead)
{ for (i = 0; i < nDelete; i++)
{
SpGistLeafTuple it;
it = (SpGistLeafTuple) PageGetItem(current->page,
PageGetItemId(current->page, toDelete[i]));
Assert(it->tupstate == SPGIST_LIVE);
/* For the moment, assume we can include the new leaf tuple */
*includeNew = true;
/* If there's only the new leaf tuple, don't select allTheSame mode */ if (in->nTuples <= 1) returnfalse;
/* If tuple set doesn't fit on one page, ignore the new tuple in test */
limit = tooBig ? in->nTuples - 1 : in->nTuples;
/* Check to see if more than one node is populated */
theNode = out->mapTuplesToNodes[0]; for (i = 1; i < limit; i++)
{ if (out->mapTuplesToNodes[i] != theNode) returnfalse;
}
/* Nope, so override the picksplit function's decisions */
/* If the new tuple is in its own node, it can't be included in split */ if (tooBig && out->mapTuplesToNodes[in->nTuples - 1] != theNode)
*includeNew = false;
out->nNodes = 8; /* arbitrary number of child nodes */
/* Random assignment of tuples to nodes (note we include new tuple) */ for (i = 0; i < in->nTuples; i++)
out->mapTuplesToNodes[i] = i % out->nNodes;
/* The opclass may not use node labels, but if it does, duplicate 'em */ if (out->nodeLabels)
{
Datum theLabel = out->nodeLabels[theNode];
out->nodeLabels = (Datum *) palloc(sizeof(Datum) * out->nNodes); for (i = 0; i < out->nNodes; i++)
out->nodeLabels[i] = theLabel;
}
/* We don't touch the prefix or the leaf tuple datum assignments */
/* *Formlistofleaftupleswhichwillbedistributedassplitresult; *also,countuptheamountofspacethatwillbefreedfromcurrent. *(Notethatinthenon-rootcase,wewon'tactuallydeletetheold *tuples,onlyreplacethemwithredirectsorplaceholders.)
*/
nToInsert = 0;
nToDelete = 0;
spaceToDelete = 0; if (SpGistBlockIsRoot(current->blkno))
{ /* *Wearesplittingtheroot(whichuptonowisalsoaleafpage). *Itstuplesarenotlinked,soscansequentiallytogetthemall.We *ignoretheoriginalvalueofcurrent->offnum.
*/ for (i = FirstOffsetNumber; i <= max; i++)
{
SpGistLeafTuple it;
it = (SpGistLeafTuple) PageGetItem(current->page,
PageGetItemId(current->page, i)); if (it->tupstate == SPGIST_LIVE)
{
in.datums[nToInsert] =
isNulls ? (Datum) 0 : SGLTDATUM(it, state);
oldLeafs[nToInsert] = it;
nToInsert++;
toDelete[nToDelete] = i;
nToDelete++; /* we will delete the tuple altogether, so count full space */
spaceToDelete += it->size + sizeof(ItemIdData);
} else/* tuples on root should be live */
elog(ERROR, "unexpected SPGiST tuple state: %d", it->tupstate);
}
} else
{ /* Normal case, just collect the leaf tuples in the chain */
i = current->offnum; while (i != InvalidOffsetNumber)
{
SpGistLeafTuple it;
Assert(i >= FirstOffsetNumber && i <= max);
it = (SpGistLeafTuple) PageGetItem(current->page,
PageGetItemId(current->page, i)); if (it->tupstate == SPGIST_LIVE)
{
in.datums[nToInsert] =
isNulls ? (Datum) 0 : SGLTDATUM(it, state);
oldLeafs[nToInsert] = it;
nToInsert++;
toDelete[nToDelete] = i;
nToDelete++; /* we will not delete the tuple, only replace with dead */
Assert(it->size >= SGDTSIZE);
spaceToDelete += it->size - SGDTSIZE;
} elseif (it->tupstate == SPGIST_DEAD)
{ /* We could see a DEAD tuple as first/only chain item */
Assert(i == current->offnum);
Assert(SGLT_GET_NEXTOFFSET(it) == InvalidOffsetNumber);
toDelete[nToDelete] = i;
nToDelete++; /* replacing it with redirect will save no space */
} else
elog(ERROR, "unexpected SPGiST tuple state: %d", it->tupstate);
i = SGLT_GET_NEXTOFFSET(it);
}
}
in.nTuples = nToInsert;
/* *Re-scannewleaftuplesandcountupthespaceneededundereachnode.
*/ for (i = 0; i < maxToInclude; i++)
{
n = out.mapTuplesToNodes[i]; if (n < 0 || n >= out.nNodes)
elog(ERROR, "inconsistent result of SPGiST picksplit function");
leafSizes[n] += newLeafs[i]->size + sizeof(ItemIdData);
}
/* *Toperformthesplit,wemustinsertanewinnertuple,whichcan'tgo *onaleafpage;andunlesswearesplittingtherootpage,wemustthen *updatetheparenttuple'sdownlinktopointtotheinnertuple.If *thereisroom,we'llputthenewinnertupleonthesamepageasthe *parenttuple,otherwiseweneedanothernon-leafbuffer.Butifthe *parentpageistheroot,wecan'taddthenewinnertuplethere, *becausetherootpagemusthaveonlyoneinnertuple.
*/
xlrec.initInner = false; if (parent->buffer != InvalidBuffer &&
!SpGistBlockIsRoot(parent->blkno) &&
(SpGistPageGetFreeSpace(parent->page, 1) >=
innerTuple->size + sizeof(ItemIdData)))
{ /* New inner tuple will fit on parent page */
newInnerBuffer = parent->buffer;
} elseif (parent->buffer != InvalidBuffer)
{ /* Send tuple to page with next triple parity (see README) */
newInnerBuffer = SpGistGetBuffer(index,
GBUF_INNER_PARITY(parent->blkno + 1) |
(isNulls ? GBUF_NULLS : 0),
innerTuple->size + sizeof(ItemIdData),
&xlrec.initInner);
} else
{ /* Root page split ... inner tuple will go to root page */
newInnerBuffer = InvalidBuffer;
}
/* *Thenewleaftuplesconvertedfromtheexistingonesshouldrequirethe *sameorlessspace,andthereforeshouldallfitontoonepage *(althoughthat'snotnecessarilythecurrentpage,sincewecan't *deletetheoldtuplesbutonlyreplacethemwithplaceholders). *However,theincomingnewtuplemightnotalsofit,inwhichcasewe *mightneedanotherpicksplitcycletoreduceitsomemore. * *Ifthere'snotroomtoputeverythingbackontothecurrentpage,then *wedecideonaper-nodebasiswhichtuplesgotothenewpage.(Wedo *itlikethatbecauseleaftuplechainscan'tcrosspages,sowemust *placeallleaftuplesbelongingtothesameparentnodeonthesame *page.) * *Ifwearesplittingtherootpage(turningitfromaleafpageintoan *innerpage),thennoleaftuplescangobacktothecurrentpage;they *mustallgosomewhereelse.
*/ if (!SpGistBlockIsRoot(current->blkno))
currentFreeSpace = PageGetExactFreeSpace(current->page) + spaceToDelete; else
currentFreeSpace = 0; /* prevent assigning any tuples to current */
xlrec.initDest = false;
if (totalLeafSizes <= currentFreeSpace)
{ /* All the leaf tuples will fit on current page */
newLeafBuffer = InvalidBuffer; /* mark new leaf tuple as included in insertions, if allowed */ if (includeNew)
{
nToInsert++;
insertedNew = true;
} for (i = 0; i < nToInsert; i++)
leafPageSelect[i] = 0; /* signifies current page */
} elseif (in.nTuples == 1 && totalLeafSizes > SPGIST_PAGE_CAPACITY)
{ /* *We'retryingtosplitupalongvaluebyrepeatedsuffixing,but *it'snotgoingtofityet.Don'tbotherallocatingasecondleaf *bufferthatwewon'tbeabletouse.
*/
newLeafBuffer = InvalidBuffer;
Assert(includeNew);
Assert(nToInsert == 0);
} else
{ /* We will need another leaf page */
uint8 *nodePageSelect; int curspace; int newspace;
curspace = currentFreeSpace;
newspace = PageGetExactFreeSpace(BufferGetPage(newLeafBuffer)); for (i = 0; i < out.nNodes; i++)
{ if (leafSizes[i] <= curspace)
{
nodePageSelect[i] = 0; /* signifies current page */
curspace -= leafSizes[i];
} else
{
nodePageSelect[i] = 1; /* signifies new leaf page */
newspace -= leafSizes[i];
}
} if (curspace >= 0 && newspace >= 0)
{ /* Successful assignment, so we can include the new leaf tuple */ if (includeNew)
{
nToInsert++;
insertedNew = true;
}
} elseif (includeNew)
{ /* We must exclude the new leaf tuple from the split */ int nodeOfNewTuple = out.mapTuplesToNodes[in.nTuples - 1];
/* Repeat the node assignment process --- should succeed now */
curspace = currentFreeSpace;
newspace = PageGetExactFreeSpace(BufferGetPage(newLeafBuffer)); for (i = 0; i < out.nNodes; i++)
{ if (leafSizes[i] <= curspace)
{
nodePageSelect[i] = 0; /* signifies current page */
curspace -= leafSizes[i];
} else
{
nodePageSelect[i] = 1; /* signifies new leaf page */
newspace -= leafSizes[i];
}
} if (curspace < 0 || newspace < 0)
elog(ERROR, "failed to divide leaf tuple groups across pages");
} else
{ /* oops, we already excluded new tuple ... should not get here */
elog(ERROR, "failed to divide leaf tuple groups across pages");
} /* Expand the per-node assignments to be shown per leaf tuple */ for (i = 0; i < nToInsert; i++)
{
n = out.mapTuplesToNodes[i];
leafPageSelect[i] = nodePageSelect[n];
}
}
/* Parent page, if different from inner page */ if (parent->buffer != InvalidBuffer)
{ if (parent->buffer != current->buffer)
XLogRegisterBuffer(3, parent->buffer, REGBUF_STANDARD); else
Assert(xlrec.innerIsParent);
}
/* Issue the WAL record */
recptr = XLogInsert(RM_SPGIST_ID, XLOG_SPGIST_PICKSPLIT);
/* Update page LSNs on all affected pages */ if (newLeafBuffer != InvalidBuffer)
{
Page page = BufferGetPage(newLeafBuffer);
PageSetLSN(page, recptr);
}
if (saveCurrent.buffer != InvalidBuffer)
{
Page page = BufferGetPage(saveCurrent.buffer);
PageSetLSN(page, recptr);
}
PageSetLSN(current->page, recptr);
if (parent->buffer != InvalidBuffer)
{
PageSetLSN(parent->page, recptr);
}
}
END_CRIT_SECTION();
/* Update local free-space cache and unlock buffers */ if (newLeafBuffer != InvalidBuffer)
{
SpGistSetLastUsedPage(index, newLeafBuffer);
UnlockReleaseBuffer(newLeafBuffer);
} if (saveCurrent.buffer != InvalidBuffer)
{
SpGistSetLastUsedPage(index, saveCurrent.buffer);
UnlockReleaseBuffer(saveCurrent.buffer);
}
/* Release previous parent buffer if any */ if (parent->buffer != InvalidBuffer &&
parent->buffer != current->buffer)
{
SpGistSetLastUsedPage(index, parent->buffer);
UnlockReleaseBuffer(parent->buffer);
}
/* Repoint parent to specified node of current inner tuple */
parent->blkno = current->blkno;
parent->buffer = current->buffer;
parent->page = current->page;
parent->offnum = current->offnum;
parent->node = nodeN;
/* Locate that node */
SGITITERATE(innerTuple, i, node)
{ if (i == nodeN) break;
}
if (i != nodeN)
elog(ERROR, "failed to find requested node %d in SPGiST inner tuple",
nodeN);
/* Point current to the downlink location, if any */ if (ItemPointerIsValid(&node->t_tid))
{
current->blkno = ItemPointerGetBlockNumber(&node->t_tid);
current->offnum = ItemPointerGetOffsetNumber(&node->t_tid);
} else
{ /* Downlink is empty, so we'll need to find a new page */
current->blkno = InvalidBlockNumber;
current->offnum = InvalidOffsetNumber;
}
/* Should not be applied to nulls */
Assert(!SpGistPageStoresNulls(current->page));
/* Construct new inner tuple with additional node */
newInnerTuple = addNode(state, innerTuple, nodeLabel, nodeN);
/* Prepare WAL record */
STORE_STATE(state, xlrec.stateSrc);
xlrec.offnum = current->offnum;
/* we don't fill these unless we need to change the parent downlink */
xlrec.parentBlk = -1;
xlrec.offnumParent = InvalidOffsetNumber;
xlrec.nodeI = 0;
/* we don't fill these unless tuple has to be moved */
xlrec.offnumNew = InvalidOffsetNumber;
xlrec.newPage = false;
PageIndexTupleDelete(current->page, current->offnum); if (PageAddItem(current->page,
(Item) newInnerTuple, newInnerTuple->size,
current->offnum, false, false) != current->offnum)
elog(ERROR, "failed to add item of size %u to SPGiST index page",
newInnerTuple->size);
MarkBufferDirty(current->buffer);
if (RelationNeedsWAL(index) && !state->isBuild)
{
XLogRecPtr recptr;
/* *Let'sjustmakerealsurenewcurrentisn'tsameasold.Rightnow *that'simpossible,butifSpGistGetBufferevergotsmartenoughto *deleteplaceholdertuplesbeforecheckingspace,maybeitwouldn't *beimpossible.ThecasewouldappeartoworkexceptthatWAL *replaywouldbesubtlywrong,soIthinkamereassertisn'tenough *here.
*/ if (current->blkno == saveCurrent.blkno)
elog(ERROR, "SPGiST new buffer shouldn't be same as old buffer");
PageIndexTupleDelete(saveCurrent.page, saveCurrent.offnum); if (PageAddItem(saveCurrent.page, (Item) dt, dt->size,
saveCurrent.offnum, false, false) != saveCurrent.offnum)
elog(ERROR, "failed to add item of size %u to SPGiST index page",
dt->size);
if (state->isBuild)
SpGistPageGetOpaque(saveCurrent.page)->nPlaceholder++; else
SpGistPageGetOpaque(saveCurrent.page)->nRedirection++;
MarkBufferDirty(saveCurrent.buffer);
if (RelationNeedsWAL(index) && !state->isBuild)
{
XLogRecPtr recptr; int flags;
XLogBeginInsert();
/* orig page */
XLogRegisterBuffer(0, saveCurrent.buffer, REGBUF_STANDARD); /* new page */
flags = REGBUF_STANDARD; if (xlrec.newPage)
flags |= REGBUF_WILL_INIT;
XLogRegisterBuffer(1, current->buffer, flags); /* parent page (if different from orig and new) */ if (xlrec.parentBlk == 2)
XLogRegisterBuffer(2, parent->buffer, REGBUF_STANDARD);
/* we don't bother to check if any of these are redundant */
PageSetLSN(current->page, recptr);
PageSetLSN(parent->page, recptr);
PageSetLSN(saveCurrent.page, recptr);
}
END_CRIT_SECTION();
/* Release saveCurrent if it's not same as current or parent */ if (saveCurrent.buffer != current->buffer &&
saveCurrent.buffer != parent->buffer)
{
SpGistSetLastUsedPage(index, saveCurrent.buffer);
UnlockReleaseBuffer(saveCurrent.buffer);
}
}
}
/* it must fit in the space that innerTuple now occupies */ if (prefixTuple->size > innerTuple->size)
elog(ERROR, "SPGiST inner-tuple split must not produce longer prefix");
/* Likewise, ensure that any INCLUDE values are not toasted */ for (int i = spgFirstIncludeColumn; i < leafDescriptor->natts; i++)
{ if (!isnulls[i])
{ if (TupleDescCompactAttr(leafDescriptor, i)->attlen == -1)
leafDatums[i] = PointerGetDatum(PG_DETOAST_DATUM(datums[i])); else
leafDatums[i] = datums[i];
} else
leafDatums[i] = (Datum) 0;
}
/* *Computespaceneededforaleaftuplecontainingthegivendata.
*/
leafSize = SpGistGetLeafTupleSize(leafDescriptor, leafDatums, isnulls); /* Account for an item pointer, too */
leafSize += sizeof(ItemIdData);
/* *Ifitisn'tgonnafit,andtheopclasscan'treducethedatumsizeby *suffixing,bailoutnowratherthandoingalotofuselesswork.
*/ if (leafSize > SPGIST_PAGE_CAPACITY &&
(isnull || !state->config.longValuesOK))
ereport(ERROR,
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
errmsg("index row size %zu exceeds maximum %zu for index \"%s\"",
leafSize - sizeof(ItemIdData),
SPGIST_PAGE_CAPACITY - sizeof(ItemIdData),
RelationGetRelationName(index)),
errhint("Values larger than a buffer page cannot be indexed.")));
bestLeafSize = leafSize;
/* *Bailoutifquerycancelispending.Wemusthavethissomewhere *intheloopsinceabrokenopclasscouldproduceaninfinite *picksplitloop.However,becausewe'llbeholdingbufferlock(s) *afterthefirstiteration,ProcessInterrupts()wouldn'tbeableto *throwacancelerrorhere.Hence,ifweseethataninterruptis *pending,breakoutoftheloopanddealwiththesituationbelow. *Setresult=falsebecausewemustrestarttheinsertionifthe *interruptisn'taquery-cancel-or-diecase.
*/ if (INTERRUPTS_PENDING_CONDITION())
{
result = false; break;
}
if (current.blkno == InvalidBlockNumber)
{ /* *Createaleafpage.IfleafSizeistoolargetofitonapage, *wewon'tactuallyusethepageyet,butitsimplifiestheAPI *fordoPickSplittoalwayshavealeafpageathand;sojust *quietlylimitourrequesttoapagesize.
*/
current.buffer =
SpGistGetBuffer(index,
GBUF_LEAF | (isnull ? GBUF_NULLS : 0),
Min(leafSize, SPGIST_PAGE_CAPACITY),
&isNew);
current.blkno = BufferGetBlockNumber(current.buffer);
} elseif (parent.buffer == InvalidBuffer)
{ /* we hold no parent-page lock, so no deadlock is possible */
current.buffer = ReadBuffer(index, current.blkno);
LockBuffer(current.buffer, BUFFER_LOCK_EXCLUSIVE);
} elseif (current.blkno != parent.blkno)
{ /* descend to a new child page */
current.buffer = ReadBuffer(index, current.blkno);
/* *Attempttoacquirelockonchildpage.Wemustbewareof *deadlockagainstanotherinsertionprocessdescendingfromthat *pagetoourparentpage(seeREADME).Ifwefailtogetlock, *abandontheinsertionandtellourcallertostartover. * *XXXthiscouldbeimproved,becausefailingtogetlockona *bufferisnotproofofadeadlocksituation;thelockmightbe *heldbyareader,orevenjustbackgroundwriter/checkpointer *process.Perhapsit'dbeworthretryingaftersleepingabit?
*/ if (!ConditionalLockBuffer(current.buffer))
{
ReleaseBuffer(current.buffer);
UnlockReleaseBuffer(parent.buffer); returnfalse;
}
} 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;
if (state->config.longValuesOK && !isnull)
{ if (leafSize < bestLeafSize)
{
ok = true;
bestLeafSize = leafSize;
numNoProgressCycles = 0;
} elseif (++numNoProgressCycles < 10)
ok = true;
} if (!ok)
ereport(ERROR,
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
errmsg("index row size %zu exceeds maximum %zu for index \"%s\"",
leafSize - sizeof(ItemIdData),
SPGIST_PAGE_CAPACITY - sizeof(ItemIdData),
RelationGetRelationName(index)),
errhint("Values larger than a buffer page cannot be indexed.")));
}
/* *LooparoundandattempttoinsertthenewleafDatumat *"current"(whichmightreferenceanexistingchild *tuple,ormightbeinvalidtoforceustofindanew *pageforthetuple).
*/ 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);
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.77Bemerkung:
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-08-08)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.