mirror of
https://github.com/postgres/postgres.git
synced 2025-07-28 23:42:10 +03:00
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.
This commit is contained in:
@ -112,6 +112,7 @@ GinFormTuple(GinState *ginstate,
|
||||
if (newsize != IndexTupleSize(itup))
|
||||
{
|
||||
itup = repalloc(itup, newsize);
|
||||
|
||||
/*
|
||||
* PostgreSQL 9.3 and earlier did not clear this new space, so we
|
||||
* might find uninitialized padding when reading tuples from disk.
|
||||
@ -431,22 +432,26 @@ entryGetLeftMostPage(GinBtree btree, Page page)
|
||||
}
|
||||
|
||||
static bool
|
||||
entryIsEnoughSpace(GinBtree btree, Buffer buf, OffsetNumber off)
|
||||
entryIsEnoughSpace(GinBtree btree, Buffer buf, OffsetNumber off,
|
||||
GinBtreeEntryInsertData *insertData)
|
||||
{
|
||||
Size itupsz = 0;
|
||||
Size releasedsz = 0;
|
||||
Size addedsz;
|
||||
Page page = BufferGetPage(buf);
|
||||
|
||||
Assert(btree->entry);
|
||||
Assert(insertData->entry);
|
||||
Assert(!GinPageIsData(page));
|
||||
|
||||
if (btree->isDelete)
|
||||
if (insertData->isDelete)
|
||||
{
|
||||
IndexTuple itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, off));
|
||||
|
||||
itupsz = MAXALIGN(IndexTupleSize(itup)) + sizeof(ItemIdData);
|
||||
releasedsz = MAXALIGN(IndexTupleSize(itup)) + sizeof(ItemIdData);
|
||||
}
|
||||
|
||||
if (PageGetFreeSpace(page) + itupsz >= MAXALIGN(IndexTupleSize(btree->entry)) + sizeof(ItemIdData))
|
||||
addedsz = MAXALIGN(IndexTupleSize(insertData->entry)) + sizeof(ItemIdData);
|
||||
|
||||
if (PageGetFreeSpace(page) + releasedsz >= addedsz)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
@ -457,42 +462,42 @@ entryIsEnoughSpace(GinBtree btree, Buffer buf, OffsetNumber off)
|
||||
* should update it, update old child blkno to new right page
|
||||
* if child split occurred
|
||||
*/
|
||||
static BlockNumber
|
||||
entryPreparePage(GinBtree btree, Page page, OffsetNumber off)
|
||||
static void
|
||||
entryPreparePage(GinBtree btree, Page page, OffsetNumber off,
|
||||
GinBtreeEntryInsertData *insertData, BlockNumber updateblkno)
|
||||
{
|
||||
BlockNumber ret = InvalidBlockNumber;
|
||||
|
||||
Assert(btree->entry);
|
||||
Assert(insertData->entry);
|
||||
Assert(!GinPageIsData(page));
|
||||
|
||||
if (btree->isDelete)
|
||||
if (insertData->isDelete)
|
||||
{
|
||||
Assert(GinPageIsLeaf(page));
|
||||
PageIndexTupleDelete(page, off);
|
||||
}
|
||||
|
||||
if (!GinPageIsLeaf(page) && btree->rightblkno != InvalidBlockNumber)
|
||||
if (!GinPageIsLeaf(page) && updateblkno != InvalidBlockNumber)
|
||||
{
|
||||
IndexTuple itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, off));
|
||||
|
||||
GinSetDownlink(itup, btree->rightblkno);
|
||||
ret = btree->rightblkno;
|
||||
GinSetDownlink(itup, updateblkno);
|
||||
}
|
||||
|
||||
btree->rightblkno = InvalidBlockNumber;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Place tuple on page and fills WAL record
|
||||
*
|
||||
* If the tuple doesn't fit, returns false without modifying the page.
|
||||
*
|
||||
* 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'.
|
||||
*/
|
||||
static bool
|
||||
entryPlaceToPage(GinBtree btree, Buffer buf, OffsetNumber off,
|
||||
void *insertPayload, BlockNumber updateblkno,
|
||||
XLogRecData **prdata)
|
||||
{
|
||||
GinBtreeEntryInsertData *insertData = insertPayload;
|
||||
Page page = BufferGetPage(buf);
|
||||
OffsetNumber placed;
|
||||
int cnt = 0;
|
||||
@ -502,13 +507,17 @@ entryPlaceToPage(GinBtree btree, Buffer buf, OffsetNumber off,
|
||||
static ginxlogInsert data;
|
||||
|
||||
/* quick exit if it doesn't fit */
|
||||
if (!entryIsEnoughSpace(btree, buf, off))
|
||||
if (!entryIsEnoughSpace(btree, buf, off, insertData))
|
||||
return false;
|
||||
|
||||
*prdata = rdata;
|
||||
data.updateBlkno = entryPreparePage(btree, page, off);
|
||||
entryPreparePage(btree, page, off, insertData, updateblkno);
|
||||
data.updateBlkno = updateblkno;
|
||||
|
||||
placed = PageAddItem(page, (Item) btree->entry, IndexTupleSize(btree->entry), off, false, false);
|
||||
placed = PageAddItem(page,
|
||||
(Item) insertData->entry,
|
||||
IndexTupleSize(insertData->entry),
|
||||
off, false, false);
|
||||
if (placed != off)
|
||||
elog(ERROR, "failed to add item to index page in \"%s\"",
|
||||
RelationGetRelationName(btree->index));
|
||||
@ -517,7 +526,7 @@ entryPlaceToPage(GinBtree btree, Buffer buf, OffsetNumber off,
|
||||
data.blkno = BufferGetBlockNumber(buf);
|
||||
data.offset = off;
|
||||
data.nitem = 1;
|
||||
data.isDelete = btree->isDelete;
|
||||
data.isDelete = insertData->isDelete;
|
||||
data.isData = false;
|
||||
data.isLeaf = GinPageIsLeaf(page) ? TRUE : FALSE;
|
||||
|
||||
@ -545,12 +554,10 @@ entryPlaceToPage(GinBtree btree, Buffer buf, OffsetNumber off,
|
||||
cnt++;
|
||||
|
||||
rdata[cnt].buffer = InvalidBuffer;
|
||||
rdata[cnt].data = (char *) btree->entry;
|
||||
rdata[cnt].len = IndexTupleSize(btree->entry);
|
||||
rdata[cnt].data = (char *) insertData->entry;
|
||||
rdata[cnt].len = IndexTupleSize(insertData->entry);
|
||||
rdata[cnt].next = NULL;
|
||||
|
||||
btree->entry = NULL;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -561,8 +568,11 @@ entryPlaceToPage(GinBtree btree, Buffer buf, OffsetNumber off,
|
||||
* an equal number!
|
||||
*/
|
||||
static Page
|
||||
entrySplitPage(GinBtree btree, Buffer lbuf, Buffer rbuf, OffsetNumber off, XLogRecData **prdata)
|
||||
entrySplitPage(GinBtree btree, Buffer lbuf, Buffer rbuf, OffsetNumber off,
|
||||
void *insertPayload,
|
||||
BlockNumber updateblkno, XLogRecData **prdata)
|
||||
{
|
||||
GinBtreeEntryInsertData *insertData = insertPayload;
|
||||
OffsetNumber i,
|
||||
maxoff,
|
||||
separator = InvalidOffsetNumber;
|
||||
@ -583,8 +593,9 @@ entrySplitPage(GinBtree btree, Buffer lbuf, Buffer rbuf, OffsetNumber off, XLogR
|
||||
|
||||
*prdata = rdata;
|
||||
data.leftChildBlkno = (GinPageIsLeaf(lpage)) ?
|
||||
InvalidOffsetNumber : GinGetDownlink(btree->entry);
|
||||
data.updateBlkno = entryPreparePage(btree, lpage, off);
|
||||
InvalidOffsetNumber : GinGetDownlink(insertData->entry);
|
||||
data.updateBlkno = updateblkno;
|
||||
entryPreparePage(btree, lpage, off, insertData, updateblkno);
|
||||
|
||||
maxoff = PageGetMaxOffsetNumber(lpage);
|
||||
ptr = tupstore;
|
||||
@ -593,8 +604,8 @@ entrySplitPage(GinBtree btree, Buffer lbuf, Buffer rbuf, OffsetNumber off, XLogR
|
||||
{
|
||||
if (i == off)
|
||||
{
|
||||
size = MAXALIGN(IndexTupleSize(btree->entry));
|
||||
memcpy(ptr, btree->entry, size);
|
||||
size = MAXALIGN(IndexTupleSize(insertData->entry));
|
||||
memcpy(ptr, insertData->entry, size);
|
||||
ptr += size;
|
||||
totalsize += size + sizeof(ItemIdData);
|
||||
}
|
||||
@ -608,8 +619,8 @@ entrySplitPage(GinBtree btree, Buffer lbuf, Buffer rbuf, OffsetNumber off, XLogR
|
||||
|
||||
if (off == maxoff + 1)
|
||||
{
|
||||
size = MAXALIGN(IndexTupleSize(btree->entry));
|
||||
memcpy(ptr, btree->entry, size);
|
||||
size = MAXALIGN(IndexTupleSize(insertData->entry));
|
||||
memcpy(ptr, insertData->entry, size);
|
||||
ptr += size;
|
||||
totalsize += size + sizeof(ItemIdData);
|
||||
}
|
||||
@ -667,20 +678,23 @@ entrySplitPage(GinBtree btree, Buffer lbuf, Buffer rbuf, OffsetNumber off, XLogR
|
||||
}
|
||||
|
||||
/*
|
||||
* Prepare the state in 'btree' for inserting a downlink for given buffer.
|
||||
* Construct insertion payload for inserting the downlink for given buffer.
|
||||
*/
|
||||
static void
|
||||
static void *
|
||||
entryPrepareDownlink(GinBtree btree, Buffer lbuf)
|
||||
{
|
||||
GinBtreeEntryInsertData *insertData;
|
||||
Page lpage = BufferGetPage(lbuf);
|
||||
BlockNumber lblkno = BufferGetBlockNumber(lbuf);
|
||||
IndexTuple itup;
|
||||
|
||||
itup = getRightMostTuple(lpage);
|
||||
|
||||
btree->entry = GinFormInteriorTuple(itup,
|
||||
lpage,
|
||||
BufferGetBlockNumber(lbuf));
|
||||
btree->rightblkno = GinPageGetOpaque(lpage)->rightlink;
|
||||
insertData = palloc(sizeof(GinBtreeEntryInsertData));
|
||||
insertData->entry = GinFormInteriorTuple(itup, lpage, lblkno);
|
||||
insertData->isDelete = false;
|
||||
|
||||
return insertData;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -724,6 +738,7 @@ ginPrepareEntryScan(GinBtree btree, OffsetNumber attnum,
|
||||
memset(btree, 0, sizeof(GinBtreeData));
|
||||
|
||||
btree->index = ginstate->index;
|
||||
btree->rootBlkno = GIN_ROOT_BLKNO;
|
||||
btree->ginstate = ginstate;
|
||||
|
||||
btree->findChildPage = entryLocateEntry;
|
||||
@ -743,5 +758,4 @@ ginPrepareEntryScan(GinBtree btree, OffsetNumber attnum,
|
||||
btree->entryAttnum = attnum;
|
||||
btree->entryKey = key;
|
||||
btree->entryCategory = category;
|
||||
btree->isDelete = FALSE;
|
||||
}
|
||||
|
Reference in New Issue
Block a user