@@ -280,80 +280,115 @@ ginFindParents(GinBtree btree, GinBtreeStack *stack,
280280}
281281
282282/*
283- * Insert value (stored in GinBtree) to tree described by stack
284- *
285- * During an index build, buildStats is non-null and the counters
286- * it contains are incremented as needed.
283+ * Returns true if the insertion is done, false if the page was split and
284+ * downlink insertion is pending.
287285 *
288- * NB: the passed-in stack is freed, as though by freeGinBtreeStack .
286+ * stack->buffer is locked on entry, and is kept locked .
289287 */
290- void
291- ginInsertValue (GinBtree btree , GinBtreeStack * stack , GinStatsData * buildStats )
288+ static bool
289+ ginPlaceToPage (GinBtree btree , BlockNumber rootBlkno , GinBtreeStack * stack ,
290+ GinStatsData * buildStats )
292291{
293- GinBtreeStack * parent ;
294- BlockNumber rootBlkno ;
295- Page page ,
296- rpage ,
297- lpage ;
292+ Page page = BufferGetPage (stack -> buffer );
293+ XLogRecData * rdata ;
294+ bool fit ;
298295
299- /* extract root BlockNumber from stack */
300- Assert (stack != NULL );
301- parent = stack ;
302- while (parent -> parent )
303- parent = parent -> parent ;
304- rootBlkno = parent -> blkno ;
305- Assert (BlockNumberIsValid (rootBlkno ));
296+ START_CRIT_SECTION ();
297+ fit = btree -> placeToPage (btree , stack -> buffer , stack -> off , & rdata );
298+ if (fit )
299+ {
300+ MarkBufferDirty (stack -> buffer );
306301
307- /* this loop crawls up the stack until the insertion is complete */
308- for (;;)
302+ if (RelationNeedsWAL (btree -> index ))
303+ {
304+ XLogRecPtr recptr ;
305+
306+ recptr = XLogInsert (RM_GIN_ID , XLOG_GIN_INSERT , rdata );
307+ PageSetLSN (page , recptr );
308+ }
309+
310+ END_CRIT_SECTION ();
311+
312+ return true;
313+ }
314+ else
309315 {
310- XLogRecData * rdata ;
316+ /* Didn't fit, have to split */
317+ Buffer rbuffer ;
318+ Page newlpage ;
311319 BlockNumber savedRightLink ;
312- bool fit ;
320+ GinBtreeStack * parent ;
321+ Page lpage ,
322+ rpage ;
323+
324+ END_CRIT_SECTION ();
325+
326+ rbuffer = GinNewBuffer (btree -> index );
313327
314- page = BufferGetPage (stack -> buffer );
315328 savedRightLink = GinPageGetOpaque (page )-> rightlink ;
316329
317- START_CRIT_SECTION ();
318- fit = btree -> placeToPage (btree , stack -> buffer , stack -> off , & rdata );
319- if (fit )
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+ if (buildStats )
320340 {
341+ if (btree -> isData )
342+ buildStats -> nDataPages ++ ;
343+ else
344+ buildStats -> nEntryPages ++ ;
345+ }
346+
347+ parent = stack -> parent ;
348+
349+ if (parent == NULL )
350+ {
351+ /*
352+ * split root, so we need to allocate new left page and place
353+ * pointer on root to left and right page
354+ */
355+ Buffer lbuffer = GinNewBuffer (btree -> index );
356+
357+ ((ginxlogSplit * ) (rdata -> data ))-> isRootSplit = TRUE;
358+ ((ginxlogSplit * ) (rdata -> data ))-> rrlink = InvalidBlockNumber ;
359+
360+ lpage = BufferGetPage (lbuffer );
361+ rpage = BufferGetPage (rbuffer );
362+
363+ GinPageGetOpaque (rpage )-> rightlink = InvalidBlockNumber ;
364+ GinPageGetOpaque (newlpage )-> rightlink = BufferGetBlockNumber (rbuffer );
365+ ((ginxlogSplit * ) (rdata -> data ))-> lblkno = BufferGetBlockNumber (lbuffer );
366+
367+ START_CRIT_SECTION ();
368+
369+ GinInitBuffer (stack -> buffer , GinPageGetOpaque (newlpage )-> flags & ~GIN_LEAF );
370+ PageRestoreTempPage (newlpage , lpage );
371+ btree -> fillRoot (btree , stack -> buffer , lbuffer , rbuffer );
372+
373+ MarkBufferDirty (rbuffer );
374+ MarkBufferDirty (lbuffer );
321375 MarkBufferDirty (stack -> buffer );
322376
323377 if (RelationNeedsWAL (btree -> index ))
324378 {
325379 XLogRecPtr recptr ;
326380
327- recptr = XLogInsert (RM_GIN_ID , XLOG_GIN_INSERT , rdata );
381+ recptr = XLogInsert (RM_GIN_ID , XLOG_GIN_SPLIT , rdata );
328382 PageSetLSN (page , recptr );
383+ PageSetLSN (lpage , recptr );
384+ PageSetLSN (rpage , recptr );
329385 }
330386
331- LockBuffer (stack -> buffer , GIN_UNLOCK );
332- END_CRIT_SECTION ();
333-
334- freeGinBtreeStack (stack );
335-
336- return ;
337- }
338- else
339- {
340- /* Didn't fit, have to split */
341- Buffer rbuffer ;
342- Page newlpage ;
343-
387+ UnlockReleaseBuffer (rbuffer );
388+ UnlockReleaseBuffer (lbuffer );
344389 END_CRIT_SECTION ();
345390
346- rbuffer = GinNewBuffer (btree -> index );
347-
348- /*
349- * newlpage is a pointer to memory page, it is not associated with
350- * a buffer. stack->buffer is not touched yet.
351- */
352- newlpage = btree -> splitPage (btree , stack -> buffer , rbuffer , stack -> off , & rdata );
353-
354- ((ginxlogSplit * ) (rdata -> data ))-> rootBlkno = rootBlkno ;
355-
356- /* During index build, count the newly-split page */
391+ /* During index build, count the newly-added root page */
357392 if (buildStats )
358393 {
359394 if (btree -> isData )
@@ -362,98 +397,83 @@ ginInsertValue(GinBtree btree, GinBtreeStack *stack, GinStatsData *buildStats)
362397 buildStats -> nEntryPages ++ ;
363398 }
364399
365- parent = stack -> parent ;
366-
367- if (parent == NULL )
368- {
369- /*
370- * split root, so we need to allocate new left page and place
371- * pointer on root to left and right page
372- */
373- Buffer lbuffer = GinNewBuffer (btree -> index );
374-
375- ((ginxlogSplit * ) (rdata -> data ))-> isRootSplit = TRUE;
376- ((ginxlogSplit * ) (rdata -> data ))-> rrlink = InvalidBlockNumber ;
377-
378- page = BufferGetPage (stack -> buffer );
379- lpage = BufferGetPage (lbuffer );
380- rpage = BufferGetPage (rbuffer );
381-
382- GinPageGetOpaque (rpage )-> rightlink = InvalidBlockNumber ;
383- GinPageGetOpaque (newlpage )-> rightlink = BufferGetBlockNumber (rbuffer );
384- ((ginxlogSplit * ) (rdata -> data ))-> lblkno = BufferGetBlockNumber (lbuffer );
385-
386- START_CRIT_SECTION ();
387-
388- GinInitBuffer (stack -> buffer , GinPageGetOpaque (newlpage )-> flags & ~GIN_LEAF );
389- PageRestoreTempPage (newlpage , lpage );
390- btree -> fillRoot (btree , stack -> buffer , lbuffer , rbuffer );
391-
392- MarkBufferDirty (rbuffer );
393- MarkBufferDirty (lbuffer );
394- MarkBufferDirty (stack -> buffer );
400+ return true;
401+ }
402+ else
403+ {
404+ /* split non-root page */
405+ ((ginxlogSplit * ) (rdata -> data ))-> isRootSplit = FALSE;
406+ ((ginxlogSplit * ) (rdata -> data ))-> rrlink = savedRightLink ;
395407
396- if (RelationNeedsWAL (btree -> index ))
397- {
398- XLogRecPtr recptr ;
408+ lpage = BufferGetPage (stack -> buffer );
409+ rpage = BufferGetPage (rbuffer );
399410
400- recptr = XLogInsert (RM_GIN_ID , XLOG_GIN_SPLIT , rdata );
401- PageSetLSN (page , recptr );
402- PageSetLSN (lpage , recptr );
403- PageSetLSN (rpage , recptr );
404- }
411+ GinPageGetOpaque (rpage )-> rightlink = savedRightLink ;
412+ GinPageGetOpaque (newlpage )-> rightlink = BufferGetBlockNumber (rbuffer );
405413
406- UnlockReleaseBuffer (rbuffer );
407- UnlockReleaseBuffer (lbuffer );
408- LockBuffer (stack -> buffer , GIN_UNLOCK );
409- END_CRIT_SECTION ();
414+ START_CRIT_SECTION ();
415+ PageRestoreTempPage (newlpage , lpage );
410416
411- freeGinBtreeStack (stack );
417+ MarkBufferDirty (rbuffer );
418+ MarkBufferDirty (stack -> buffer );
412419
413- /* During index build, count the newly-added root page */
414- if (buildStats )
415- {
416- if (btree -> isData )
417- buildStats -> nDataPages ++ ;
418- else
419- buildStats -> nEntryPages ++ ;
420- }
420+ if (RelationNeedsWAL (btree -> index ))
421+ {
422+ XLogRecPtr recptr ;
421423
422- return ;
424+ recptr = XLogInsert (RM_GIN_ID , XLOG_GIN_SPLIT , rdata );
425+ PageSetLSN (lpage , recptr );
426+ PageSetLSN (rpage , recptr );
423427 }
424- else
425- {
426- /* split non-root page */
427- ((ginxlogSplit * ) (rdata -> data ))-> isRootSplit = FALSE;
428- ((ginxlogSplit * ) (rdata -> data ))-> rrlink = savedRightLink ;
428+ UnlockReleaseBuffer (rbuffer );
429+ END_CRIT_SECTION ();
429430
430- lpage = BufferGetPage (stack -> buffer );
431- rpage = BufferGetPage (rbuffer );
431+ return false;
432+ }
433+ }
434+ }
432435
433- GinPageGetOpaque (rpage )-> rightlink = savedRightLink ;
434- GinPageGetOpaque (newlpage )-> rightlink = BufferGetBlockNumber (rbuffer );
436+ /*
437+ * Insert value (stored in GinBtree) to tree described by stack
438+ *
439+ * During an index build, buildStats is non-null and the counters
440+ * it contains are incremented as needed.
441+ *
442+ * NB: the passed-in stack is freed, as though by freeGinBtreeStack.
443+ */
444+ void
445+ ginInsertValue (GinBtree btree , GinBtreeStack * stack , GinStatsData * buildStats )
446+ {
447+ GinBtreeStack * parent ;
448+ BlockNumber rootBlkno ;
449+ 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 ));
435458
436- START_CRIT_SECTION ();
437- PageRestoreTempPage (newlpage , lpage );
459+ /* this loop crawls up the stack until the insertion is complete */
460+ for (;;)
461+ {
462+ bool done ;
438463
439- MarkBufferDirty (rbuffer );
440- MarkBufferDirty (stack -> buffer );
464+ done = ginPlaceToPage (btree , rootBlkno , stack , buildStats );
441465
442- if (RelationNeedsWAL (btree -> index ))
443- {
444- XLogRecPtr recptr ;
466+ /* just to be extra sure we don't delete anything by accident... */
467+ btree -> isDelete = FALSE;
445468
446- recptr = XLogInsert (RM_GIN_ID , XLOG_GIN_SPLIT , rdata );
447- PageSetLSN (lpage , recptr );
448- PageSetLSN (rpage , recptr );
449- }
450- UnlockReleaseBuffer (rbuffer );
451- END_CRIT_SECTION ();
452- }
469+ if (done )
470+ {
471+ LockBuffer (stack -> buffer , GIN_UNLOCK );
472+ freeGinBtreeStack (stack );
473+ break ;
453474 }
454475
455476 btree -> prepareDownlink (btree , stack -> buffer );
456- btree -> isDelete = FALSE;
457477
458478 /* search parent to lock */
459479 LockBuffer (parent -> buffer , GIN_EXCLUSIVE );
0 commit comments