1919#include "utils/rel.h"
2020
2121/*
22- * Locks buffer by needed method for search.
22+ * Lock buffer by needed method for search.
2323 */
2424static int
2525ginTraverseLock (Buffer buffer , bool searchMode )
@@ -53,23 +53,23 @@ ginTraverseLock(Buffer buffer, bool searchMode)
5353}
5454
5555/*
56- * Descends the tree to the leaf page that contains or would contain the
57- * key we're searching for. The key should already be filled in 'btree',
58- * in tree-type specific manner. If btree->fullScan is true, descends to the
56+ * Descend the tree to the leaf page that contains or would contain the key
57+ * we're searching for. The key should already be filled in 'btree', in
58+ * tree-type specific manner. If btree->fullScan is true, descends to the
5959 * leftmost leaf page.
6060 *
6161 * If 'searchmode' is false, on return stack->buffer is exclusively locked,
6262 * and the stack represents the full path to the root. Otherwise stack->buffer
6363 * is share-locked, and stack->parent is NULL.
6464 */
6565GinBtreeStack *
66- ginFindLeafPage (GinBtree btree , BlockNumber rootBlkno , bool searchMode )
66+ ginFindLeafPage (GinBtree btree , bool searchMode )
6767{
6868 GinBtreeStack * stack ;
6969
7070 stack = (GinBtreeStack * ) palloc (sizeof (GinBtreeStack ));
71- stack -> blkno = rootBlkno ;
72- stack -> buffer = ReadBuffer (btree -> index , rootBlkno );
71+ stack -> blkno = btree -> rootBlkno ;
72+ stack -> buffer = ReadBuffer (btree -> index , btree -> rootBlkno );
7373 stack -> parent = NULL ;
7474 stack -> predictNumber = 1 ;
7575
@@ -89,7 +89,7 @@ ginFindLeafPage(GinBtree btree, BlockNumber rootBlkno, bool searchMode)
8989 * ok, page is correctly locked, we should check to move right ..,
9090 * root never has a right link, so small optimization
9191 */
92- while (btree -> fullScan == FALSE && stack -> blkno != rootBlkno &&
92+ while (btree -> fullScan == FALSE && stack -> blkno != btree -> rootBlkno &&
9393 btree -> isMoveRight (btree , page ))
9494 {
9595 BlockNumber rightlink = GinPageGetOpaque (page )-> rightlink ;
@@ -146,7 +146,7 @@ ginStepRight(Buffer buffer, Relation index, int lockmode)
146146 Page page = BufferGetPage (buffer );
147147 bool isLeaf = GinPageIsLeaf (page );
148148 bool isData = GinPageIsData (page );
149- BlockNumber blkno = GinPageGetOpaque (page )-> rightlink ;
149+ BlockNumber blkno = GinPageGetOpaque (page )-> rightlink ;
150150
151151 nextbuffer = ReadBuffer (index , blkno );
152152 LockBuffer (nextbuffer , lockmode );
@@ -158,10 +158,10 @@ ginStepRight(Buffer buffer, Relation index, int lockmode)
158158 elog (ERROR , "right sibling of GIN page is of different type" );
159159
160160 /*
161- * Given the proper lock sequence above, we should never land on a
162- * deleted page.
161+ * Given the proper lock sequence above, we should never land on a deleted
162+ * page.
163163 */
164- if (GinPageIsDeleted (page ))
164+ if (GinPageIsDeleted (page ))
165165 elog (ERROR , "right sibling of GIN page was deleted" );
166166
167167 return nextbuffer ;
@@ -183,14 +183,12 @@ freeGinBtreeStack(GinBtreeStack *stack)
183183}
184184
185185/*
186- * Try to find parent for current stack position, returns correct
187- * parent and child's offset in stack->parent.
188- * Function should never release root page to prevent conflicts
189- * with vacuum process
186+ * Try to find parent for current stack position. Returns correct parent and
187+ * child's offset in stack->parent. The root page is never released, to
188+ * to prevent conflict with vacuum process.
190189 */
191190void
192- ginFindParents (GinBtree btree , GinBtreeStack * stack ,
193- BlockNumber rootBlkno )
191+ ginFindParents (GinBtree btree , GinBtreeStack * stack )
194192{
195193 Page page ;
196194 Buffer buffer ;
@@ -204,8 +202,8 @@ ginFindParents(GinBtree btree, GinBtreeStack *stack,
204202 {
205203 /* XLog mode... */
206204 root = (GinBtreeStack * ) palloc (sizeof (GinBtreeStack ));
207- root -> blkno = rootBlkno ;
208- root -> buffer = ReadBuffer (btree -> index , rootBlkno );
205+ root -> blkno = btree -> rootBlkno ;
206+ root -> buffer = ReadBuffer (btree -> index , btree -> rootBlkno );
209207 LockBuffer (root -> buffer , GIN_EXCLUSIVE );
210208 root -> parent = NULL ;
211209 }
@@ -221,8 +219,8 @@ ginFindParents(GinBtree btree, GinBtreeStack *stack,
221219 root = root -> parent ;
222220 }
223221
224- Assert (root -> blkno == rootBlkno );
225- Assert (BufferGetBlockNumber (root -> buffer ) == rootBlkno );
222+ Assert (root -> blkno == btree -> rootBlkno );
223+ Assert (BufferGetBlockNumber (root -> buffer ) == btree -> rootBlkno );
226224 LockBuffer (root -> buffer , GIN_EXCLUSIVE );
227225 }
228226 root -> off = InvalidOffsetNumber ;
@@ -268,7 +266,7 @@ ginFindParents(GinBtree btree, GinBtreeStack *stack,
268266 ptr = (GinBtreeStack * ) palloc (sizeof (GinBtreeStack ));
269267 ptr -> blkno = blkno ;
270268 ptr -> buffer = buffer ;
271- ptr -> parent = root ; /* it's may be wrong, but in next call we will
269+ ptr -> parent = root ; /* it may be wrong, but in next call we will
272270 * correct */
273271 ptr -> off = offset ;
274272 stack -> parent = ptr ;
@@ -280,21 +278,35 @@ ginFindParents(GinBtree btree, GinBtreeStack *stack,
280278}
281279
282280/*
283- * Returns true if the insertion is done, false if the page was split and
284- * downlink insertion is pending.
281+ * Insert a new item to a page.
282+ *
283+ * Returns true if the insertion was finished. On false, the page was split and
284+ * the parent needs to be updated. (a root split returns true as it doesn't
285+ * need any further action by the caller to complete)
286+ *
287+ * When inserting a downlink to a internal page, the existing item at the
288+ * given location is updated to point to 'updateblkno'.
285289 *
286290 * stack->buffer is locked on entry, and is kept locked.
287291 */
288292static bool
289- ginPlaceToPage (GinBtree btree , BlockNumber rootBlkno , GinBtreeStack * stack ,
293+ ginPlaceToPage (GinBtree btree , GinBtreeStack * stack ,
294+ void * insertdata , BlockNumber updateblkno ,
290295 GinStatsData * buildStats )
291296{
292297 Page page = BufferGetPage (stack -> buffer );
293298 XLogRecData * rdata ;
294299 bool fit ;
295300
301+ /*
302+ * Try to put the incoming tuple on the page. If it doesn't fit,
303+ * placeToPage method will return false and leave the page unmodified, and
304+ * we'll have to split the page.
305+ */
296306 START_CRIT_SECTION ();
297- fit = btree -> placeToPage (btree , stack -> buffer , stack -> off , & rdata );
307+ fit = btree -> placeToPage (btree , stack -> buffer , stack -> off ,
308+ insertdata , updateblkno ,
309+ & rdata );
298310 if (fit )
299311 {
300312 MarkBufferDirty (stack -> buffer );
@@ -324,18 +336,7 @@ ginPlaceToPage(GinBtree btree, BlockNumber rootBlkno, GinBtreeStack *stack,
324336 END_CRIT_SECTION ();
325337
326338 rbuffer = GinNewBuffer (btree -> index );
327-
328- savedRightLink = GinPageGetOpaque (page )-> rightlink ;
329-
330- /*
331- * newlpage is a pointer to memory page, it is not associated with
332- * a buffer. stack->buffer is not touched yet.
333- */
334- newlpage = btree -> splitPage (btree , stack -> buffer , rbuffer , stack -> off , & rdata );
335-
336- ((ginxlogSplit * ) (rdata -> data ))-> rootBlkno = rootBlkno ;
337-
338- /* During index build, count the newly-split page */
339+ /* During index build, count the new page */
339340 if (buildStats )
340341 {
341342 if (btree -> isData )
@@ -344,6 +345,18 @@ ginPlaceToPage(GinBtree btree, BlockNumber rootBlkno, GinBtreeStack *stack,
344345 buildStats -> nEntryPages ++ ;
345346 }
346347
348+ savedRightLink = GinPageGetOpaque (page )-> rightlink ;
349+
350+ /*
351+ * newlpage is a pointer to memory page, it is not associated with a
352+ * buffer. stack->buffer is not touched yet.
353+ */
354+ newlpage = btree -> splitPage (btree , stack -> buffer , rbuffer , stack -> off ,
355+ insertdata , updateblkno ,
356+ & rdata );
357+
358+ ((ginxlogSplit * ) (rdata -> data ))-> rootBlkno = btree -> rootBlkno ;
359+
347360 parent = stack -> parent ;
348361
349362 if (parent == NULL )
@@ -354,6 +367,15 @@ ginPlaceToPage(GinBtree btree, BlockNumber rootBlkno, GinBtreeStack *stack,
354367 */
355368 Buffer lbuffer = GinNewBuffer (btree -> index );
356369
370+ /* During index build, count the new page */
371+ if (buildStats )
372+ {
373+ if (btree -> isData )
374+ buildStats -> nDataPages ++ ;
375+ else
376+ buildStats -> nEntryPages ++ ;
377+ }
378+
357379 ((ginxlogSplit * ) (rdata -> data ))-> isRootSplit = TRUE;
358380 ((ginxlogSplit * ) (rdata -> data ))-> rrlink = InvalidBlockNumber ;
359381
@@ -434,46 +456,27 @@ ginPlaceToPage(GinBtree btree, BlockNumber rootBlkno, GinBtreeStack *stack,
434456}
435457
436458/*
437- * Insert value (stored in GinBtree) to tree described by stack
459+ * Finish a split by inserting the downlink for the new page to parent.
438460 *
439- * During an index build, buildStats is non-null and the counters
440- * it contains are incremented as needed.
461+ * On entry, stack->buffer is exclusively locked.
441462 *
442463 * NB: the passed-in stack is freed, as though by freeGinBtreeStack.
443464 */
444465void
445- ginInsertValue (GinBtree btree , GinBtreeStack * stack , GinStatsData * buildStats )
466+ ginFinishSplit (GinBtree btree , GinBtreeStack * stack , GinStatsData * buildStats )
446467{
447- GinBtreeStack * parent ;
448- BlockNumber rootBlkno ;
449468 Page page ;
450-
451- /* extract root BlockNumber from stack */
452- Assert (stack != NULL );
453- parent = stack ;
454- while (parent -> parent )
455- parent = parent -> parent ;
456- rootBlkno = parent -> blkno ;
457- Assert (BlockNumberIsValid (rootBlkno ));
469+ bool done ;
458470
459471 /* this loop crawls up the stack until the insertion is complete */
460- for (;;)
472+ do
461473 {
462- bool done ;
463-
464- done = ginPlaceToPage (btree , rootBlkno , stack , buildStats );
465-
466- /* just to be extra sure we don't delete anything by accident... */
467- btree -> isDelete = FALSE;
468-
469- if (done )
470- {
471- LockBuffer (stack -> buffer , GIN_UNLOCK );
472- freeGinBtreeStack (stack );
473- break ;
474- }
474+ GinBtreeStack * parent = stack -> parent ;
475+ void * insertdata ;
476+ BlockNumber updateblkno ;
475477
476- btree -> prepareDownlink (btree , stack -> buffer );
478+ insertdata = btree -> prepareDownlink (btree , stack -> buffer );
479+ updateblkno = GinPageGetOpaque (BufferGetPage (stack -> buffer ))-> rightlink ;
477480
478481 /* search parent to lock */
479482 LockBuffer (parent -> buffer , GIN_EXCLUSIVE );
@@ -491,7 +494,7 @@ ginInsertValue(GinBtree btree, GinBtreeStack *stack, GinStatsData *buildStats)
491494 * plain search...
492495 */
493496 LockBuffer (parent -> buffer , GIN_UNLOCK );
494- ginFindParents (btree , stack , rootBlkno );
497+ ginFindParents (btree , stack );
495498 parent = stack -> parent ;
496499 Assert (parent != NULL );
497500 break ;
@@ -502,8 +505,49 @@ ginInsertValue(GinBtree btree, GinBtreeStack *stack, GinStatsData *buildStats)
502505 page = BufferGetPage (parent -> buffer );
503506 }
504507
508+ /* release the child */
505509 UnlockReleaseBuffer (stack -> buffer );
506510 pfree (stack );
507511 stack = parent ;
512+
513+ /* insert the downlink to parent */
514+ done = ginPlaceToPage (btree , stack ,
515+ insertdata , updateblkno ,
516+ buildStats );
517+ pfree (insertdata );
518+ } while (!done );
519+ LockBuffer (stack -> buffer , GIN_UNLOCK );
520+
521+ /* free the rest of the stack */
522+ freeGinBtreeStack (stack );
523+ }
524+
525+ /*
526+ * Insert a value to tree described by stack.
527+ *
528+ * The value to be inserted is given in 'insertdata'. Its format depends
529+ * on whether this is an entry or data tree, ginInsertValue just passes it
530+ * through to the tree-specific callback function.
531+ *
532+ * During an index build, buildStats is non-null and the counters it contains
533+ * are incremented as needed.
534+ *
535+ * NB: the passed-in stack is freed, as though by freeGinBtreeStack.
536+ */
537+ void
538+ ginInsertValue (GinBtree btree , GinBtreeStack * stack , void * insertdata ,
539+ GinStatsData * buildStats )
540+ {
541+ bool done ;
542+
543+ done = ginPlaceToPage (btree , stack ,
544+ insertdata , InvalidBlockNumber ,
545+ buildStats );
546+ if (done )
547+ {
548+ LockBuffer (stack -> buffer , GIN_UNLOCK );
549+ freeGinBtreeStack (stack );
508550 }
551+ else
552+ ginFinishSplit (btree , stack , buildStats );
509553}
0 commit comments