1
0
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:
Heikki Linnakangas
2013-11-27 15:43:05 +02:00
parent 4118f7e8ed
commit ce5326eed3
7 changed files with 310 additions and 219 deletions

View File

@ -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;
}