1 /*-------------------------------------------------------------------------
4 * interface routines for the postgres GiST index access method.
7 * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
8 * Portions Copyright (c) 1994, Regents of the University of California
11 * src/backend/access/gist/gist.c
13 *-------------------------------------------------------------------------
17 #include "access/genam.h"
18 #include "access/gist_private.h"
19 #include "catalog/index.h"
20 #include "miscadmin.h"
21 #include "storage/bufmgr.h"
22 #include "storage/indexfsm.h"
23 #include "utils/memutils.h"
25 /* Working state for gistbuild and its callback */
35 /* non-export function prototypes */
36 static void gistbuildCallback(Relation index,
42 static void gistdoinsert(Relation r,
45 GISTSTATE *GISTstate);
46 static void gistfindleaf(GISTInsertState *state,
47 GISTSTATE *giststate);
50 #define ROTATEDIST(d) do { \
51 SplitedPageLayout *tmp=(SplitedPageLayout*)palloc(sizeof(SplitedPageLayout)); \
52 memset(tmp,0,sizeof(SplitedPageLayout)); \
53 tmp->block.blkno = InvalidBlockNumber; \
54 tmp->buffer = InvalidBuffer; \
61 * Create and return a temporary memory context for use by GiST. We
62 * _always_ invoke user-provided methods in a temporary memory
63 * context, so that memory leaks in those functions cannot cause
64 * problems. Also, we use some additional temporary contexts in the
65 * GiST code itself, to avoid the need to do some awkward manual
69 createTempGistContext(void)
71 return AllocSetContextCreate(CurrentMemoryContext,
72 "GiST temporary context",
73 ALLOCSET_DEFAULT_MINSIZE,
74 ALLOCSET_DEFAULT_INITSIZE,
75 ALLOCSET_DEFAULT_MAXSIZE);
79 * Routine to build an index. Basically calls insert over and over.
81 * XXX: it would be nice to implement some sort of bulk-loading
82 * algorithm, but it is not clear how to do that.
85 gistbuild(PG_FUNCTION_ARGS)
87 Relation heap = (Relation) PG_GETARG_POINTER(0);
88 Relation index = (Relation) PG_GETARG_POINTER(1);
89 IndexInfo *indexInfo = (IndexInfo *) PG_GETARG_POINTER(2);
90 IndexBuildResult *result;
92 GISTBuildState buildstate;
97 * We expect to be called exactly once for any index relation. If that's
98 * not the case, big trouble's what we have.
100 if (RelationGetNumberOfBlocks(index) != 0)
101 elog(ERROR, "index \"%s\" already contains data",
102 RelationGetRelationName(index));
104 /* no locking is needed */
105 initGISTstate(&buildstate.giststate, index);
107 /* initialize the root page */
108 buffer = gistNewBuffer(index);
109 Assert(BufferGetBlockNumber(buffer) == GIST_ROOT_BLKNO);
110 page = BufferGetPage(buffer);
112 START_CRIT_SECTION();
114 GISTInitBuffer(buffer, F_LEAF);
116 MarkBufferDirty(buffer);
118 if (!index->rd_istemp)
123 rdata.data = (char *) &(index->rd_node);
124 rdata.len = sizeof(RelFileNode);
125 rdata.buffer = InvalidBuffer;
128 recptr = XLogInsert(RM_GIST_ID, XLOG_GIST_CREATE_INDEX, &rdata);
129 PageSetLSN(page, recptr);
130 PageSetTLI(page, ThisTimeLineID);
133 PageSetLSN(page, GetXLogRecPtrForTemp());
135 UnlockReleaseBuffer(buffer);
139 /* build the index */
140 buildstate.numindexattrs = indexInfo->ii_NumIndexAttrs;
141 buildstate.indtuples = 0;
144 * create a temporary memory context that is reset once for each tuple
145 * inserted into the index
147 buildstate.tmpCtx = createTempGistContext();
149 /* do the heap scan */
150 reltuples = IndexBuildHeapScan(heap, index, indexInfo, true,
151 gistbuildCallback, (void *) &buildstate);
153 /* okay, all heap tuples are indexed */
154 MemoryContextDelete(buildstate.tmpCtx);
156 freeGISTstate(&buildstate.giststate);
161 result = (IndexBuildResult *) palloc(sizeof(IndexBuildResult));
163 result->heap_tuples = reltuples;
164 result->index_tuples = buildstate.indtuples;
166 PG_RETURN_POINTER(result);
170 * Per-tuple callback from IndexBuildHeapScan
173 gistbuildCallback(Relation index,
180 GISTBuildState *buildstate = (GISTBuildState *) state;
182 MemoryContext oldCtx;
184 oldCtx = MemoryContextSwitchTo(buildstate->tmpCtx);
186 /* form an index tuple and point it at the heap tuple */
187 itup = gistFormTuple(&buildstate->giststate, index,
188 values, isnull, true /* size is currently bogus */ );
189 itup->t_tid = htup->t_self;
192 * Since we already have the index relation locked, we call gistdoinsert
193 * directly. Normal access method calls dispatch through gistinsert,
194 * which locks the relation for write. This is the right thing to do if
195 * you're inserting single tups, but not when you're initializing the
196 * whole index at once.
198 * In this path we respect the fillfactor setting, whereas insertions
199 * after initial build do not.
201 gistdoinsert(index, itup,
202 RelationGetTargetPageFreeSpace(index, GIST_DEFAULT_FILLFACTOR),
203 &buildstate->giststate);
205 buildstate->indtuples += 1;
206 MemoryContextSwitchTo(oldCtx);
207 MemoryContextReset(buildstate->tmpCtx);
211 * gistinsert -- wrapper for GiST tuple insertion.
213 * This is the public interface routine for tuple insertion in GiSTs.
214 * It doesn't do any work; just locks the relation and passes the buck.
217 gistinsert(PG_FUNCTION_ARGS)
219 Relation r = (Relation) PG_GETARG_POINTER(0);
220 Datum *values = (Datum *) PG_GETARG_POINTER(1);
221 bool *isnull = (bool *) PG_GETARG_POINTER(2);
222 ItemPointer ht_ctid = (ItemPointer) PG_GETARG_POINTER(3);
225 Relation heapRel = (Relation) PG_GETARG_POINTER(4);
226 IndexUniqueCheck checkUnique = (IndexUniqueCheck) PG_GETARG_INT32(5);
230 MemoryContext oldCtx;
231 MemoryContext insertCtx;
233 insertCtx = createTempGistContext();
234 oldCtx = MemoryContextSwitchTo(insertCtx);
236 initGISTstate(&giststate, r);
238 itup = gistFormTuple(&giststate, r,
239 values, isnull, true /* size is currently bogus */ );
240 itup->t_tid = *ht_ctid;
242 gistdoinsert(r, itup, 0, &giststate);
245 freeGISTstate(&giststate);
246 MemoryContextSwitchTo(oldCtx);
247 MemoryContextDelete(insertCtx);
249 PG_RETURN_BOOL(false);
254 * Workhouse routine for doing insertion into a GiST index. Note that
255 * this routine assumes it is invoked in a short-lived memory context,
256 * so it does not bother releasing palloc'd allocations.
259 gistdoinsert(Relation r, IndexTuple itup, Size freespace, GISTSTATE *giststate)
261 GISTInsertState state;
263 memset(&state, 0, sizeof(GISTInsertState));
265 state.itup = (IndexTuple *) palloc(sizeof(IndexTuple));
266 state.itup[0] = (IndexTuple) palloc(IndexTupleSize(itup));
267 memcpy(state.itup[0], itup, IndexTupleSize(itup));
269 state.freespace = freespace;
271 state.key = itup->t_tid;
272 state.needInsertComplete = true;
274 state.stack = (GISTInsertStack *) palloc0(sizeof(GISTInsertStack));
275 state.stack->blkno = GIST_ROOT_BLKNO;
277 gistfindleaf(&state, giststate);
278 gistmakedeal(&state, giststate);
282 gistplacetopage(GISTInsertState *state, GISTSTATE *giststate)
284 bool is_splitted = false;
285 bool is_leaf = (GistPageIsLeaf(state->stack->page)) ? true : false;
288 * if (!is_leaf) remove old key: This node's key has been modified, either
289 * because a child split occurred or because we needed to adjust our key
290 * for an insert in a child node. Therefore, remove the old version of
293 * for WAL replay, in the non-split case we handle this by setting up a
294 * one-element todelete array; in the split case, it's handled implicitly
295 * because the tuple vector passed to gistSplit won't include this tuple.
297 * XXX: If we want to change fillfactors between node and leaf, fillfactor
298 * = (is_leaf ? state->leaf_fillfactor : state->node_fillfactor)
300 if (gistnospace(state->stack->page, state->itup, state->ituplen,
301 is_leaf ? InvalidOffsetNumber : state->stack->childoffnum,
304 /* no space for insertion */
307 SplitedPageLayout *dist = NULL,
309 BlockNumber rrlink = InvalidBlockNumber;
315 * Form index tuples vector to split: remove old tuple if t's needed
316 * and add new tuples to vector
318 itvec = gistextractpage(state->stack->page, &tlen);
321 /* on inner page we should remove old tuple */
322 int pos = state->stack->childoffnum - FirstOffsetNumber;
326 memmove(itvec + pos, itvec + pos + 1, sizeof(IndexTuple) * (tlen - pos));
328 itvec = gistjoinvector(itvec, &tlen, state->itup, state->ituplen);
329 dist = gistSplit(state->r, state->stack->page, itvec, tlen, giststate);
331 state->itup = (IndexTuple *) palloc(sizeof(IndexTuple) * tlen);
334 if (state->stack->blkno != GIST_ROOT_BLKNO)
337 * if non-root split then we should not allocate new buffer, but
338 * we must create temporary page to operate
340 dist->buffer = state->stack->buffer;
341 dist->page = PageGetTempPageCopySpecial(BufferGetPage(dist->buffer));
343 /* clean all flags except F_LEAF */
344 GistPageGetOpaque(dist->page)->flags = (is_leaf) ? F_LEAF : 0;
347 /* make new pages and fills them */
348 for (ptr = dist; ptr; ptr = ptr->next)
354 if (ptr->buffer == InvalidBuffer)
356 ptr->buffer = gistNewBuffer(state->r);
357 GISTInitBuffer(ptr->buffer, (is_leaf) ? F_LEAF : 0);
358 ptr->page = BufferGetPage(ptr->buffer);
360 ptr->block.blkno = BufferGetBlockNumber(ptr->buffer);
363 * fill page, we can do it because all these pages are new (ie not
364 * linked in tree or masked by temp page
366 data = (char *) (ptr->list);
367 for (i = 0; i < ptr->block.num; i++)
369 if (PageAddItem(ptr->page, (Item) data, IndexTupleSize((IndexTuple) data), i + FirstOffsetNumber, false, false) == InvalidOffsetNumber)
370 elog(ERROR, "failed to add item to index page in \"%s\"", RelationGetRelationName(state->r));
371 data += IndexTupleSize((IndexTuple) data);
374 /* set up ItemPointer and remember it for parent */
375 ItemPointerSetBlockNumber(&(ptr->itup->t_tid), ptr->block.blkno);
376 state->itup[state->ituplen] = ptr->itup;
380 /* saves old rightlink */
381 if (state->stack->blkno != GIST_ROOT_BLKNO)
382 rrlink = GistPageGetOpaque(dist->page)->rightlink;
384 START_CRIT_SECTION();
387 * must mark buffers dirty before XLogInsert, even though we'll still
388 * be changing their opaque fields below. set up right links.
390 for (ptr = dist; ptr; ptr = ptr->next)
392 MarkBufferDirty(ptr->buffer);
393 GistPageGetOpaque(ptr->page)->rightlink = (ptr->next) ?
394 ptr->next->block.blkno : rrlink;
397 /* restore splitted non-root page */
398 if (state->stack->blkno != GIST_ROOT_BLKNO)
400 PageRestoreTempPage(dist->page, BufferGetPage(dist->buffer));
401 dist->page = BufferGetPage(dist->buffer);
404 if (!state->r->rd_istemp)
409 rdata = formSplitRdata(state->r->rd_node, state->stack->blkno,
410 is_leaf, &(state->key), dist);
412 recptr = XLogInsert(RM_GIST_ID, XLOG_GIST_PAGE_SPLIT, rdata);
414 for (ptr = dist; ptr; ptr = ptr->next)
416 PageSetLSN(ptr->page, recptr);
417 PageSetTLI(ptr->page, ThisTimeLineID);
422 for (ptr = dist; ptr; ptr = ptr->next)
424 PageSetLSN(ptr->page, GetXLogRecPtrForTemp());
429 oldnsn = GistPageGetOpaque(dist->page)->nsn;
430 if (state->stack->blkno == GIST_ROOT_BLKNO)
431 /* if root split we should put initial value */
432 oldnsn = PageGetLSN(dist->page);
434 for (ptr = dist; ptr; ptr = ptr->next)
436 /* only for last set oldnsn */
437 GistPageGetOpaque(ptr->page)->nsn = (ptr->next) ?
438 PageGetLSN(ptr->page) : oldnsn;
442 * release buffers, if it was a root split then release all buffers
443 * because we create all buffers
445 ptr = (state->stack->blkno == GIST_ROOT_BLKNO) ? dist : dist->next;
446 for (; ptr; ptr = ptr->next)
447 UnlockReleaseBuffer(ptr->buffer);
449 if (state->stack->blkno == GIST_ROOT_BLKNO)
451 gistnewroot(state->r, state->stack->buffer, state->itup, state->ituplen, &(state->key));
452 state->needInsertComplete = false;
460 START_CRIT_SECTION();
463 PageIndexTupleDelete(state->stack->page, state->stack->childoffnum);
464 gistfillbuffer(state->stack->page, state->itup, state->ituplen, InvalidOffsetNumber);
466 MarkBufferDirty(state->stack->buffer);
468 if (!state->r->rd_istemp)
470 OffsetNumber noffs = 0,
477 /* only on inner page we should delete previous version */
478 offs[0] = state->stack->childoffnum;
482 rdata = formUpdateRdata(state->r->rd_node, state->stack->buffer,
484 state->itup, state->ituplen,
487 recptr = XLogInsert(RM_GIST_ID, XLOG_GIST_PAGE_UPDATE, rdata);
488 PageSetLSN(state->stack->page, recptr);
489 PageSetTLI(state->stack->page, ThisTimeLineID);
492 PageSetLSN(state->stack->page, GetXLogRecPtrForTemp());
494 if (state->stack->blkno == GIST_ROOT_BLKNO)
495 state->needInsertComplete = false;
499 if (state->ituplen > 1)
500 { /* previous is_splitted==true */
503 * child was splited, so we must form union for insertion in
506 IndexTuple newtup = gistunion(state->r, state->itup, state->ituplen, giststate);
508 ItemPointerSetBlockNumber(&(newtup->t_tid), state->stack->blkno);
509 state->itup[0] = newtup;
515 * itup[0] store key to adjust parent, we set it to valid to
516 * correct check by GistTupleIsInvalid macro in gistgetadjusted()
518 ItemPointerSetBlockNumber(&(state->itup[0]->t_tid), state->stack->blkno);
519 GistTupleSetValid(state->itup[0]);
526 * returns stack of pages, all pages in stack are pinned, and
531 gistfindleaf(GISTInsertState *state, GISTSTATE *giststate)
535 GISTPageOpaque opaque;
538 * walk down, We don't lock page for a long time, but so we should be
539 * ready to recheck path in a bad case... We remember, that page->lsn
540 * should never be invalid.
544 if (XLogRecPtrIsInvalid(state->stack->lsn))
545 state->stack->buffer = ReadBuffer(state->r, state->stack->blkno);
546 LockBuffer(state->stack->buffer, GIST_SHARE);
547 gistcheckpage(state->r, state->stack->buffer);
549 state->stack->page = (Page) BufferGetPage(state->stack->buffer);
550 opaque = GistPageGetOpaque(state->stack->page);
552 state->stack->lsn = PageGetLSN(state->stack->page);
553 Assert(state->r->rd_istemp || !XLogRecPtrIsInvalid(state->stack->lsn));
555 if (state->stack->blkno != GIST_ROOT_BLKNO &&
556 XLByteLT(state->stack->parent->lsn, opaque->nsn))
559 * caused split non-root page is detected, go up to parent to
562 UnlockReleaseBuffer(state->stack->buffer);
563 state->stack = state->stack->parent;
567 if (!GistPageIsLeaf(state->stack->page))
570 * This is an internal page, so continue to walk down the tree. We
571 * find the child node that has the minimum insertion penalty and
572 * recursively invoke ourselves to modify that node. Once the
573 * recursive call returns, we may need to adjust the parent node
574 * for two reasons: the child node split, or the key in this node
575 * needs to be adjusted for the newly inserted key below us.
577 GISTInsertStack *item = (GISTInsertStack *) palloc0(sizeof(GISTInsertStack));
579 state->stack->childoffnum = gistchoose(state->r, state->stack->page, state->itup[0], giststate);
581 iid = PageGetItemId(state->stack->page, state->stack->childoffnum);
582 idxtuple = (IndexTuple) PageGetItem(state->stack->page, iid);
583 item->blkno = ItemPointerGetBlockNumber(&(idxtuple->t_tid));
584 LockBuffer(state->stack->buffer, GIST_UNLOCK);
586 item->parent = state->stack;
589 state->stack->child = item;
594 /* be carefull, during unlock/lock page may be changed... */
595 LockBuffer(state->stack->buffer, GIST_UNLOCK);
596 LockBuffer(state->stack->buffer, GIST_EXCLUSIVE);
597 state->stack->page = (Page) BufferGetPage(state->stack->buffer);
598 opaque = GistPageGetOpaque(state->stack->page);
600 if (state->stack->blkno == GIST_ROOT_BLKNO)
603 * the only page can become inner instead of leaf is a root
604 * page, so for root we should recheck it
606 if (!GistPageIsLeaf(state->stack->page))
609 * very rarely situation: during unlock/lock index with
610 * number of pages = 1 was increased
612 LockBuffer(state->stack->buffer, GIST_UNLOCK);
617 * we don't need to check root split, because checking
618 * leaf/inner is enough to recognize split for root
622 else if (XLByteLT(state->stack->parent->lsn, opaque->nsn))
625 * detecting split during unlock/lock, so we should find
626 * better child on parent
630 UnlockReleaseBuffer(state->stack->buffer);
632 state->stack = state->stack->parent;
636 state->stack->lsn = PageGetLSN(state->stack->page);
638 /* ok we found a leaf page and it X-locked */
643 /* now state->stack->(page, buffer and blkno) points to leaf page */
647 * Traverse the tree to find path from root page to specified "child" block.
649 * returns from the beginning of closest parent;
651 * To prevent deadlocks, this should lock only one page simultaneously.
654 gistFindPath(Relation r, BlockNumber child)
662 GISTInsertStack *top,
667 top = tail = (GISTInsertStack *) palloc0(sizeof(GISTInsertStack));
668 top->blkno = GIST_ROOT_BLKNO;
670 while (top && top->blkno != child)
672 buffer = ReadBuffer(r, top->blkno);
673 LockBuffer(buffer, GIST_SHARE);
674 gistcheckpage(r, buffer);
675 page = (Page) BufferGetPage(buffer);
677 if (GistPageIsLeaf(page))
679 /* we can safety go away, follows only leaf pages */
680 UnlockReleaseBuffer(buffer);
684 top->lsn = PageGetLSN(page);
686 if (top->parent && XLByteLT(top->parent->lsn, GistPageGetOpaque(page)->nsn) &&
687 GistPageGetOpaque(page)->rightlink != InvalidBlockNumber /* sanity check */ )
689 /* page splited while we thinking of... */
690 ptr = (GISTInsertStack *) palloc0(sizeof(GISTInsertStack));
691 ptr->blkno = GistPageGetOpaque(page)->rightlink;
692 ptr->childoffnum = InvalidOffsetNumber;
699 maxoff = PageGetMaxOffsetNumber(page);
701 for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
703 iid = PageGetItemId(page, i);
704 idxtuple = (IndexTuple) PageGetItem(page, iid);
705 blkno = ItemPointerGetBlockNumber(&(idxtuple->t_tid));
708 OffsetNumber poff = InvalidOffsetNumber;
710 /* make childs links */
715 ptr->parent->child = ptr;
716 /* move childoffnum.. */
719 /* first iteration */
720 poff = ptr->parent->childoffnum;
721 ptr->parent->childoffnum = ptr->childoffnum;
725 OffsetNumber tmp = ptr->parent->childoffnum;
727 ptr->parent->childoffnum = poff;
732 top->childoffnum = i;
733 UnlockReleaseBuffer(buffer);
738 /* Install next inner page to the end of stack */
739 ptr = (GISTInsertStack *) palloc0(sizeof(GISTInsertStack));
741 ptr->childoffnum = i; /* set offsetnumber of child to child
750 UnlockReleaseBuffer(buffer);
759 * Returns X-locked parent of stack page
763 gistFindCorrectParent(Relation r, GISTInsertStack *child)
765 GISTInsertStack *parent = child->parent;
767 LockBuffer(parent->buffer, GIST_EXCLUSIVE);
768 gistcheckpage(r, parent->buffer);
769 parent->page = (Page) BufferGetPage(parent->buffer);
771 /* here we don't need to distinguish between split and page update */
772 if (parent->childoffnum == InvalidOffsetNumber || !XLByteEQ(parent->lsn, PageGetLSN(parent->page)))
774 /* parent is changed, look child in right links until found */
779 GISTInsertStack *ptr;
783 maxoff = PageGetMaxOffsetNumber(parent->page);
784 for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
786 iid = PageGetItemId(parent->page, i);
787 idxtuple = (IndexTuple) PageGetItem(parent->page, iid);
788 if (ItemPointerGetBlockNumber(&(idxtuple->t_tid)) == child->blkno)
791 parent->childoffnum = i;
796 parent->blkno = GistPageGetOpaque(parent->page)->rightlink;
797 UnlockReleaseBuffer(parent->buffer);
798 if (parent->blkno == InvalidBlockNumber)
801 * end of chain and still didn't found parent, It's very-very
802 * rare situation when root splited
805 parent->buffer = ReadBuffer(r, parent->blkno);
806 LockBuffer(parent->buffer, GIST_EXCLUSIVE);
807 gistcheckpage(r, parent->buffer);
808 parent->page = (Page) BufferGetPage(parent->buffer);
812 * awful!!, we need search tree to find parent ... , but before we
813 * should release all old parent
816 ptr = child->parent->parent; /* child->parent already released
820 ReleaseBuffer(ptr->buffer);
824 /* ok, find new path */
825 ptr = parent = gistFindPath(r, child->blkno);
828 /* read all buffers as expected by caller */
829 /* note we don't lock them or gistcheckpage them here! */
832 ptr->buffer = ReadBuffer(r, ptr->blkno);
833 ptr->page = (Page) BufferGetPage(ptr->buffer);
837 /* install new chain of parents to stack */
838 child->parent = parent;
839 parent->child = child;
841 /* make recursive call to normal processing */
842 gistFindCorrectParent(r, child);
849 gistmakedeal(GISTInsertState *state, GISTSTATE *giststate)
860 * After this call: 1. if child page was splited, then itup contains
861 * keys for each page 2. if child page wasn't splited, then itup
862 * contains additional for adjustment of current key
865 if (state->stack->parent)
868 * X-lock parent page before proceed child, gistFindCorrectParent
869 * should find and lock it
871 gistFindCorrectParent(state->r, state->stack);
873 is_splitted = gistplacetopage(state, giststate);
875 /* parent locked above, so release child buffer */
876 UnlockReleaseBuffer(state->stack->buffer);
878 /* pop parent page from stack */
879 state->stack = state->stack->parent;
886 * child did not split, so we can check is it needed to update parent
892 iid = PageGetItemId(state->stack->page, state->stack->childoffnum);
893 oldtup = (IndexTuple) PageGetItem(state->stack->page, iid);
894 newtup = gistgetadjusted(state->r, oldtup, state->itup[0], giststate);
897 { /* not need to update key */
898 LockBuffer(state->stack->buffer, GIST_UNLOCK);
902 state->itup[0] = newtup;
906 /* release all parent buffers */
909 ReleaseBuffer(state->stack->buffer);
910 state->stack = state->stack->parent;
913 /* say to xlog that insert is completed */
914 if (state->needInsertComplete && !state->r->rd_istemp)
915 gistxlogInsertCompletion(state->r->rd_node, &(state->key), 1);
919 * gistSplit -- split a page in the tree and fill struct
920 * used for XLOG and real writes buffers. Function is recursive, ie
921 * it will split page until keys will fit in every page.
924 gistSplit(Relation r,
926 IndexTuple *itup, /* contains compressed entry */
928 GISTSTATE *giststate)
933 GistEntryVector *entryvec;
935 SplitedPageLayout *res = NULL;
937 /* generate the item array */
938 entryvec = palloc(GEVHDRSZ + (len + 1) * sizeof(GISTENTRY));
939 entryvec->n = len + 1;
941 memset(v.spl_lisnull, TRUE, sizeof(bool) * giststate->tupdesc->natts);
942 memset(v.spl_risnull, TRUE, sizeof(bool) * giststate->tupdesc->natts);
943 gistSplitByKey(r, page, itup, len, giststate,
946 /* form left and right vector */
947 lvectup = (IndexTuple *) palloc(sizeof(IndexTuple) * (len + 1));
948 rvectup = (IndexTuple *) palloc(sizeof(IndexTuple) * (len + 1));
950 for (i = 0; i < v.splitVector.spl_nleft; i++)
951 lvectup[i] = itup[v.splitVector.spl_left[i] - 1];
953 for (i = 0; i < v.splitVector.spl_nright; i++)
954 rvectup[i] = itup[v.splitVector.spl_right[i] - 1];
956 /* finalize splitting (may need another split) */
957 if (!gistfitpage(rvectup, v.splitVector.spl_nright))
959 res = gistSplit(r, page, rvectup, v.splitVector.spl_nright, giststate);
964 res->block.num = v.splitVector.spl_nright;
965 res->list = gistfillitupvec(rvectup, v.splitVector.spl_nright, &(res->lenlist));
966 res->itup = (v.spl_rightvalid) ? gistFormTuple(giststate, r, v.spl_rattr, v.spl_risnull, false)
967 : gist_form_invalid_tuple(GIST_ROOT_BLKNO);
970 if (!gistfitpage(lvectup, v.splitVector.spl_nleft))
972 SplitedPageLayout *resptr,
975 resptr = subres = gistSplit(r, page, lvectup, v.splitVector.spl_nleft, giststate);
977 /* install on list's tail */
979 resptr = resptr->next;
987 res->block.num = v.splitVector.spl_nleft;
988 res->list = gistfillitupvec(lvectup, v.splitVector.spl_nleft, &(res->lenlist));
989 res->itup = (v.spl_leftvalid) ? gistFormTuple(giststate, r, v.spl_lattr, v.spl_lisnull, false)
990 : gist_form_invalid_tuple(GIST_ROOT_BLKNO);
997 * buffer must be pinned and locked by caller
1000 gistnewroot(Relation r, Buffer buffer, IndexTuple *itup, int len, ItemPointer key)
1004 Assert(BufferGetBlockNumber(buffer) == GIST_ROOT_BLKNO);
1005 page = BufferGetPage(buffer);
1007 START_CRIT_SECTION();
1009 GISTInitBuffer(buffer, 0);
1010 gistfillbuffer(page, itup, len, FirstOffsetNumber);
1012 MarkBufferDirty(buffer);
1019 rdata = formUpdateRdata(r->rd_node, buffer,
1023 recptr = XLogInsert(RM_GIST_ID, XLOG_GIST_NEW_ROOT, rdata);
1024 PageSetLSN(page, recptr);
1025 PageSetTLI(page, ThisTimeLineID);
1028 PageSetLSN(page, GetXLogRecPtrForTemp());
1034 initGISTstate(GISTSTATE *giststate, Relation index)
1038 if (index->rd_att->natts > INDEX_MAX_KEYS)
1039 elog(ERROR, "numberOfAttributes %d > %d",
1040 index->rd_att->natts, INDEX_MAX_KEYS);
1042 giststate->tupdesc = index->rd_att;
1044 for (i = 0; i < index->rd_att->natts; i++)
1046 fmgr_info_copy(&(giststate->consistentFn[i]),
1047 index_getprocinfo(index, i + 1, GIST_CONSISTENT_PROC),
1048 CurrentMemoryContext);
1049 fmgr_info_copy(&(giststate->unionFn[i]),
1050 index_getprocinfo(index, i + 1, GIST_UNION_PROC),
1051 CurrentMemoryContext);
1052 fmgr_info_copy(&(giststate->compressFn[i]),
1053 index_getprocinfo(index, i + 1, GIST_COMPRESS_PROC),
1054 CurrentMemoryContext);
1055 fmgr_info_copy(&(giststate->decompressFn[i]),
1056 index_getprocinfo(index, i + 1, GIST_DECOMPRESS_PROC),
1057 CurrentMemoryContext);
1058 fmgr_info_copy(&(giststate->penaltyFn[i]),
1059 index_getprocinfo(index, i + 1, GIST_PENALTY_PROC),
1060 CurrentMemoryContext);
1061 fmgr_info_copy(&(giststate->picksplitFn[i]),
1062 index_getprocinfo(index, i + 1, GIST_PICKSPLIT_PROC),
1063 CurrentMemoryContext);
1064 fmgr_info_copy(&(giststate->equalFn[i]),
1065 index_getprocinfo(index, i + 1, GIST_EQUAL_PROC),
1066 CurrentMemoryContext);
1071 freeGISTstate(GISTSTATE *giststate)