diff options
Diffstat (limited to 'src/backend/access/gin/ginentrypage.c')
-rw-r--r-- | src/backend/access/gin/ginentrypage.c | 88 |
1 files changed, 57 insertions, 31 deletions
diff --git a/src/backend/access/gin/ginentrypage.c b/src/backend/access/gin/ginentrypage.c index 25127456480..8c0bfe9fdeb 100644 --- a/src/backend/access/gin/ginentrypage.c +++ b/src/backend/access/gin/ginentrypage.c @@ -21,7 +21,7 @@ static void entrySplitPage(GinBtree btree, Buffer origbuf, GinBtreeStack *stack, - void *insertPayload, + GinBtreeEntryInsertData *insertData, BlockNumber updateblkno, Page *newlpage, Page *newrpage); @@ -508,39 +508,57 @@ entryPreparePage(GinBtree btree, Page page, OffsetNumber off, } /* - * Place tuple on page and fills WAL record + * Prepare to insert data on an entry page. * - * If the tuple doesn't fit, returns false without modifying the page. + * If it will fit, return GPTP_INSERT after doing whatever setup is needed + * before we enter the insertion critical section. *ptp_workspace can be + * set to pass information along to the execPlaceToPage function. * - * On insertion to an internal node, in addition to inserting the given item, - * the downlink of the existing item at 'off' is updated to point to - * 'updateblkno'. + * If it won't fit, perform a page split and return two temporary page + * images into *newlpage and *newrpage, with result GPTP_SPLIT. * - * On INSERTED, registers the buffer as buffer ID 0, with data. - * On SPLIT, returns rdata that represents the split pages in *prdata. + * In neither case should the given page buffer be modified here. + * + * Note: on insertion to an internal node, in addition to inserting the given + * item, the downlink of the existing item at stack->off will be updated to + * point to updateblkno. */ static GinPlaceToPageRC -entryPlaceToPage(GinBtree btree, Buffer buf, GinBtreeStack *stack, - void *insertPayload, BlockNumber updateblkno, - Page *newlpage, Page *newrpage) +entryBeginPlaceToPage(GinBtree btree, Buffer buf, GinBtreeStack *stack, + void *insertPayload, BlockNumber updateblkno, + void **ptp_workspace, + Page *newlpage, Page *newrpage) { GinBtreeEntryInsertData *insertData = insertPayload; - Page page = BufferGetPage(buf); OffsetNumber off = stack->off; - OffsetNumber placed; - /* this must be static so it can be returned to caller. */ - static ginxlogInsertEntry data; - - /* quick exit if it doesn't fit */ + /* If it doesn't fit, deal with split case */ if (!entryIsEnoughSpace(btree, buf, off, insertData)) { - entrySplitPage(btree, buf, stack, insertPayload, updateblkno, + entrySplitPage(btree, buf, stack, insertData, updateblkno, newlpage, newrpage); - return SPLIT; + return GPTP_SPLIT; } - START_CRIT_SECTION(); + /* Else, we're ready to proceed with insertion */ + return GPTP_INSERT; +} + +/* + * Perform data insertion after beginPlaceToPage has decided it will fit. + * + * This is invoked within a critical section, and XLOG record creation (if + * needed) is already started. The target buffer is registered in slot 0. + */ +static void +entryExecPlaceToPage(GinBtree btree, Buffer buf, GinBtreeStack *stack, + void *insertPayload, BlockNumber updateblkno, + void *ptp_workspace) +{ + GinBtreeEntryInsertData *insertData = insertPayload; + Page page = BufferGetPage(buf); + OffsetNumber off = stack->off; + OffsetNumber placed; entryPreparePage(btree, page, off, insertData, updateblkno); @@ -554,34 +572,36 @@ entryPlaceToPage(GinBtree btree, Buffer buf, GinBtreeStack *stack, if (RelationNeedsWAL(btree->index)) { + /* + * This must be static, because it has to survive until XLogInsert, + * and we can't palloc here. Ugly, but the XLogInsert infrastructure + * isn't reentrant anyway. + */ + static ginxlogInsertEntry data; + data.isDelete = insertData->isDelete; data.offset = off; - XLogBeginInsert(); - XLogRegisterBuffer(0, buf, REGBUF_STANDARD); XLogRegisterBufData(0, (char *) &data, offsetof(ginxlogInsertEntry, tuple)); XLogRegisterBufData(0, (char *) insertData->entry, IndexTupleSize(insertData->entry)); } - - return INSERTED; } /* - * Place tuple and split page, original buffer(lbuf) leaves untouched, - * returns shadow pages filled with new data. - * Tuples are distributed between pages by equal size on its, not - * an equal number! + * Split entry page and insert new data. + * + * Returns new temp pages to *newlpage and *newrpage. + * The original buffer is left untouched. */ static void entrySplitPage(GinBtree btree, Buffer origbuf, GinBtreeStack *stack, - void *insertPayload, + GinBtreeEntryInsertData *insertData, BlockNumber updateblkno, Page *newlpage, Page *newrpage) { - GinBtreeEntryInsertData *insertData = insertPayload; OffsetNumber off = stack->off; OffsetNumber i, maxoff, @@ -646,6 +666,10 @@ entrySplitPage(GinBtree btree, Buffer origbuf, { itup = (IndexTuple) ptr; + /* + * Decide where to split. We try to equalize the pages' total data + * size, not number of tuples. + */ if (lsize > totalsize / 2) { if (separator == InvalidOffsetNumber) @@ -663,6 +687,7 @@ entrySplitPage(GinBtree btree, Buffer origbuf, ptr += MAXALIGN(IndexTupleSize(itup)); } + /* return temp pages to caller */ *newlpage = lpage; *newrpage = rpage; } @@ -731,7 +756,8 @@ ginPrepareEntryScan(GinBtree btree, OffsetNumber attnum, btree->isMoveRight = entryIsMoveRight; btree->findItem = entryLocateLeafEntry; btree->findChildPtr = entryFindChildPtr; - btree->placeToPage = entryPlaceToPage; + btree->beginPlaceToPage = entryBeginPlaceToPage; + btree->execPlaceToPage = entryExecPlaceToPage; btree->fillRoot = ginEntryFillRoot; btree->prepareDownlink = entryPrepareDownlink; |