Skip to content

Commit 04eee1f

Browse files
committed
More GIN refactoring.
Split off the portion of ginInsertValue that inserts the tuple to current level into a separate function, ginPlaceToPage. ginInsertValue's charter is now to recurse up the tree to insert the downlink, when a page split is required. This is in preparation for a patch to change the way incomplete splits are handled, which will need to do these operations separately. And IMHO makes the code more readable anyway.
1 parent 5010126 commit 04eee1f

File tree

1 file changed

+148
-128
lines changed

1 file changed

+148
-128
lines changed

src/backend/access/gin/ginbtree.c

Lines changed: 148 additions & 128 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy