Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit ce5326e

Browse files
committed
More GIN refactoring.
Separate the insertion payload from the more static portions of GinBtree. GinBtree now only contains information related to searching the tree, and the information of what to insert is passed separately. Add root block number to GinBtree, instead of passing it around all the functions as argument. Split off ginFinishSplit() from ginInsertValue(). ginFinishSplit is responsible for finding the parent and inserting the downlink to it.
1 parent 4118f7e commit ce5326e

File tree

7 files changed

+309
-218
lines changed

7 files changed

+309
-218
lines changed

src/backend/access/gin/ginbtree.c

Lines changed: 113 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
#include "utils/rel.h"
2020

2121
/*
22-
* Locks buffer by needed method for search.
22+
* Lock buffer by needed method for search.
2323
*/
2424
static int
2525
ginTraverseLock(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
*/
6565
GinBtreeStack *
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
*/
191190
void
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
*/
288292
static 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
*/
444465
void
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

Comments
 (0)