From fa3ecd275f51e073a385b5124763588cfb268e11 Mon Sep 17 00:00:00 2001
From: Heikki Linnakangas <heikki.linnakangas@iki.fi>
Date: Wed, 13 Nov 2013 18:15:22 +0200
Subject: [PATCH 2/4] Refactor the internal GIN B-tree interface for forming a
 downlink.

This creates a new gin-btree callback function for creating a downlink for
a page. Previously, ginxlog.c duplicated the logic used during normal
operation.
---
 src/backend/access/gin/ginbtree.c     |  1 +
 src/backend/access/gin/gindatapage.c  | 17 +++++++++++----
 src/backend/access/gin/ginentrypage.c | 40 ++++++++++++++++-------------------
 src/backend/access/gin/ginxlog.c      | 15 ++-----------
 src/include/access/gin_private.h      |  2 +-
 5 files changed, 35 insertions(+), 40 deletions(-)

diff --git a/src/backend/access/gin/ginbtree.c b/src/backend/access/gin/ginbtree.c
index 0d93c52..c4801d5 100644
--- a/src/backend/access/gin/ginbtree.c
+++ b/src/backend/access/gin/ginbtree.c
@@ -452,6 +452,7 @@ ginInsertValue(GinBtree btree, GinBtreeStack *stack, GinStatsData *buildStats)
 			}
 		}
 
+		btree->prepareDownlink(btree, stack->buffer);
 		btree->isDelete = FALSE;
 
 		/* search parent to lock */
diff --git a/src/backend/access/gin/gindatapage.c b/src/backend/access/gin/gindatapage.c
index 221b39e..908e28f 100644
--- a/src/backend/access/gin/gindatapage.c
+++ b/src/backend/access/gin/gindatapage.c
@@ -580,12 +580,20 @@ dataSplitPage(GinBtree btree, Buffer lbuf, Buffer rbuf, OffsetNumber off, XLogRe
 	rdata[1].len = MAXALIGN(maxoff * sizeofitem);
 	rdata[1].next = NULL;
 
-	/* Prepare a downlink tuple for insertion to the parent */
+	return lpage;
+}
+
+/*
+ * Prepare the state in 'btree' for inserting a downlink for given buffer.
+ */
+static void
+dataPrepareDownlink(GinBtree btree, Buffer lbuf)
+{
+	Page		lpage = BufferGetPage(lbuf);
+
 	PostingItemSetBlockNumber(&(btree->pitem), BufferGetBlockNumber(lbuf));
 	btree->pitem.key = *GinDataPageGetRightBound(lpage);
-	btree->rightblkno = BufferGetBlockNumber(rbuf);
-
-	return lpage;
+	btree->rightblkno = GinPageGetOpaque(lpage)->rightlink;
 }
 
 /*
@@ -704,6 +712,7 @@ ginPrepareDataScan(GinBtree btree, Relation index)
 	btree->placeToPage = dataPlaceToPage;
 	btree->splitPage = dataSplitPage;
 	btree->fillRoot = ginDataFillRoot;
+	btree->prepareDownlink = dataPrepareDownlink;
 
 	btree->isData = TRUE;
 	btree->isDelete = FALSE;
diff --git a/src/backend/access/gin/ginentrypage.c b/src/backend/access/gin/ginentrypage.c
index a22fd32..378bce1 100644
--- a/src/backend/access/gin/ginentrypage.c
+++ b/src/backend/access/gin/ginentrypage.c
@@ -570,8 +570,7 @@ entrySplitPage(GinBtree btree, Buffer lbuf, Buffer rbuf, OffsetNumber off, XLogR
 	Size		lsize = 0,
 				size;
 	char	   *ptr;
-	IndexTuple	itup,
-				leftrightmost = NULL;
+	IndexTuple	itup;
 	Page		page;
 	Page		lpage = PageGetTempPageCopy(BufferGetPage(lbuf));
 	Page		rpage = BufferGetPage(rbuf);
@@ -635,7 +634,6 @@ entrySplitPage(GinBtree btree, Buffer lbuf, Buffer rbuf, OffsetNumber off, XLogR
 		}
 		else
 		{
-			leftrightmost = itup;
 			lsize += MAXALIGN(IndexTupleSize(itup)) + sizeof(ItemIdData);
 		}
 
@@ -645,11 +643,6 @@ entrySplitPage(GinBtree btree, Buffer lbuf, Buffer rbuf, OffsetNumber off, XLogR
 		ptr += MAXALIGN(IndexTupleSize(itup));
 	}
 
-	btree->entry = GinFormInteriorTuple(leftrightmost, lpage,
-										BufferGetBlockNumber(lbuf));
-
-	btree->rightblkno = BufferGetBlockNumber(rbuf);
-
 	data.node = btree->index->rd_node;
 	data.rootBlkno = InvalidBlockNumber;
 	data.lblkno = BufferGetBlockNumber(lbuf);
@@ -674,19 +667,19 @@ entrySplitPage(GinBtree btree, Buffer lbuf, Buffer rbuf, OffsetNumber off, XLogR
 }
 
 /*
- * return newly allocated rightmost tuple
+ * Prepare the state in 'btree' for inserting a downlink for given buffer.
  */
-IndexTuple
-ginPageGetLinkItup(Buffer buf)
+static void
+entryPrepareDownlink(GinBtree btree, Buffer lbuf)
 {
-	IndexTuple	itup,
-				nitup;
-	Page		page = BufferGetPage(buf);
+	Page		lpage = BufferGetPage(lbuf);
+	IndexTuple	itup;
 
-	itup = getRightMostTuple(page);
-	nitup = GinFormInteriorTuple(itup, page, BufferGetBlockNumber(buf));
+	itup = getRightMostTuple(lpage);
 
-	return nitup;
+	btree->entry = GinFormInteriorTuple(itup, lpage,
+										BufferGetBlockNumber(lbuf));
+	btree->rightblkno = GinPageGetOpaque(lpage)->rightlink;
 }
 
 /*
@@ -696,17 +689,19 @@ ginPageGetLinkItup(Buffer buf)
 void
 ginEntryFillRoot(GinBtree btree, Buffer root, Buffer lbuf, Buffer rbuf)
 {
-	Page		page;
+	Page		page = BufferGetPage(root);
+	Page		lpage = BufferGetPage(lbuf);
+	Page		rpage = BufferGetPage(rbuf);
 	IndexTuple	itup;
 
-	page = BufferGetPage(root);
-
-	itup = ginPageGetLinkItup(lbuf);
+	itup = GinFormInteriorTuple(getRightMostTuple(lpage), lpage,
+								BufferGetBlockNumber(lbuf));
 	if (PageAddItem(page, (Item) itup, IndexTupleSize(itup), InvalidOffsetNumber, false, false) == InvalidOffsetNumber)
 		elog(ERROR, "failed to add item to index root page");
 	pfree(itup);
 
-	itup = ginPageGetLinkItup(rbuf);
+	itup = GinFormInteriorTuple(getRightMostTuple(rpage), rpage,
+								BufferGetBlockNumber(rbuf));
 	if (PageAddItem(page, (Item) itup, IndexTupleSize(itup), InvalidOffsetNumber, false, false) == InvalidOffsetNumber)
 		elog(ERROR, "failed to add item to index root page");
 	pfree(itup);
@@ -736,6 +731,7 @@ ginPrepareEntryScan(GinBtree btree, OffsetNumber attnum,
 	btree->placeToPage = entryPlaceToPage;
 	btree->splitPage = entrySplitPage;
 	btree->fillRoot = ginEntryFillRoot;
+	btree->prepareDownlink = entryPrepareDownlink;
 
 	btree->isData = FALSE;
 	btree->fullScan = FALSE;
diff --git a/src/backend/access/gin/ginxlog.c b/src/backend/access/gin/ginxlog.c
index 4d0ccb8..ddac343 100644
--- a/src/backend/access/gin/ginxlog.c
+++ b/src/backend/access/gin/ginxlog.c
@@ -799,31 +799,20 @@ ginContinueSplit(ginIncompleteSplit *split)
 		ginPrepareEntryScan(&btree,
 							InvalidOffsetNumber, (Datum) 0, GIN_CAT_NULL_KEY,
 							&ginstate);
-		btree.entry = ginPageGetLinkItup(buffer);
 	}
 	else
 	{
-		Page		page = BufferGetPage(buffer);
-
 		ginPrepareDataScan(&btree, reln);
-
-		PostingItemSetBlockNumber(&(btree.pitem), split->leftBlkno);
-		if (GinPageIsLeaf(page))
-			btree.pitem.key = *GinDataPageGetItemPointer(page,
-														 GinPageGetOpaque(page)->maxoff);
-		else
-			btree.pitem.key = GinDataPageGetPostingItem(page,
-														GinPageGetOpaque(page)->maxoff)->key;
 	}
 
-	btree.rightblkno = split->rightBlkno;
-
 	stack.blkno = split->leftBlkno;
 	stack.buffer = buffer;
 	stack.off = InvalidOffsetNumber;
 	stack.parent = NULL;
 
 	ginFindParents(&btree, &stack, split->rootBlkno);
+
+	btree.prepareDownlink(&btree, buffer);
 	ginInsertValue(&btree, stack.parent, NULL);
 
 	FreeFakeRelcacheEntry(reln);
diff --git a/src/include/access/gin_private.h b/src/include/access/gin_private.h
index 7491d7c..3952935 100644
--- a/src/include/access/gin_private.h
+++ b/src/include/access/gin_private.h
@@ -487,6 +487,7 @@ typedef struct GinBtreeData
 	OffsetNumber (*findChildPtr) (GinBtree, Page, BlockNumber, OffsetNumber);
 	bool		(*placeToPage) (GinBtree, Buffer, OffsetNumber, XLogRecData **);
 	Page		(*splitPage) (GinBtree, Buffer, Buffer, OffsetNumber, XLogRecData **);
+	void		(*prepareDownlink) (GinBtree, Buffer);
 	void		(*fillRoot) (GinBtree, Buffer, Buffer, Buffer);
 
 	bool		isData;
@@ -529,7 +530,6 @@ extern void ginPrepareEntryScan(GinBtree btree, OffsetNumber attnum,
 					Datum key, GinNullCategory category,
 					GinState *ginstate);
 extern void ginEntryFillRoot(GinBtree btree, Buffer root, Buffer lbuf, Buffer rbuf);
-extern IndexTuple ginPageGetLinkItup(Buffer buf);
 
 /* gindatapage.c */
 extern BlockNumber createPostingTree(Relation index,
-- 
1.8.4.rc3

