aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>2013-12-03 22:13:16 +0200
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>2013-12-03 22:34:43 +0200
commite6acb956a0505572b470daf27c145e930e689b23 (patch)
tree6fb4998211d44eea8d2eb2e9f18977e7ae915b0d
parentf67b8aeab3a543d156787de7311d4a98f228ab9f (diff)
downloadpostgresql-e6acb956a0505572b470daf27c145e930e689b23.tar.gz
postgresql-e6acb956a0505572b470daf27c145e930e689b23.zip
Fix full-page writes of internal GIN pages.
Insertion to a non-leaf GIN page didn't make a full-page image of the page, which is wrong. The code used to do it correctly, but was changed (commit 853d1c3103fa961ae6219f0281885b345593d101) because the redo-routine didn't track incomplete splits correctly when the page was restored from a full page image. Of course, that was not right way to fix it, the redo routine should've been fixed instead. The redo-routine was surreptitiously fixed in 2010 (commit 4016bdef8aded77b4903c457050622a5a1815c16), so all we need to do now is revert the code that creates the record to its original form. This doesn't change the format of the WAL record. Backpatch to all supported versions.
-rw-r--r--src/backend/access/gin/gindatapage.c42
-rw-r--r--src/backend/access/gin/ginentrypage.c42
2 files changed, 34 insertions, 50 deletions
diff --git a/src/backend/access/gin/gindatapage.c b/src/backend/access/gin/gindatapage.c
index 41dbe9fd11e..54966e411e7 100644
--- a/src/backend/access/gin/gindatapage.c
+++ b/src/backend/access/gin/gindatapage.c
@@ -382,7 +382,6 @@ dataPlaceToPage(GinBtree btree, Buffer buf, OffsetNumber off, XLogRecData **prda
{
Page page = BufferGetPage(buf);
int sizeofitem = GinSizeOfDataPageItem(page);
- int cnt = 0;
/* these must be static so they can be returned to caller */
static XLogRecData rdata[3];
@@ -402,32 +401,25 @@ dataPlaceToPage(GinBtree btree, Buffer buf, OffsetNumber off, XLogRecData **prda
data.isLeaf = GinPageIsLeaf(page) ? TRUE : FALSE;
/*
- * Prevent full page write if child's split occurs. That is needed to
- * remove incomplete splits while replaying WAL
- *
- * data.updateBlkno contains new block number (of newly created right
- * page) for recently splited page.
+ * For incomplete-split tracking, we need updateBlkno information and the
+ * inserted item even when we make a full page image of the page, so put
+ * the buffer reference in a separate XLogRecData entry.
*/
- if (data.updateBlkno == InvalidBlockNumber)
- {
- rdata[0].buffer = buf;
- rdata[0].buffer_std = FALSE;
- rdata[0].data = NULL;
- rdata[0].len = 0;
- rdata[0].next = &rdata[1];
- cnt++;
- }
+ rdata[0].buffer = buf;
+ rdata[0].buffer_std = FALSE;
+ rdata[0].data = NULL;
+ rdata[0].len = 0;
+ rdata[0].next = &rdata[1];
- rdata[cnt].buffer = InvalidBuffer;
- rdata[cnt].data = (char *) &data;
- rdata[cnt].len = sizeof(ginxlogInsert);
- rdata[cnt].next = &rdata[cnt + 1];
- cnt++;
+ rdata[1].buffer = InvalidBuffer;
+ rdata[1].data = (char *) &data;
+ rdata[1].len = sizeof(ginxlogInsert);
+ rdata[1].next = &rdata[2];
- rdata[cnt].buffer = InvalidBuffer;
- rdata[cnt].data = (GinPageIsLeaf(page)) ? ((char *) (btree->items + btree->curitem)) : ((char *) &(btree->pitem));
- rdata[cnt].len = sizeofitem;
- rdata[cnt].next = NULL;
+ rdata[2].buffer = InvalidBuffer;
+ rdata[2].data = (GinPageIsLeaf(page)) ? ((char *) (btree->items + btree->curitem)) : ((char *) &(btree->pitem));
+ rdata[2].len = sizeofitem;
+ rdata[2].next = NULL;
if (GinPageIsLeaf(page))
{
@@ -443,7 +435,7 @@ dataPlaceToPage(GinBtree btree, Buffer buf, OffsetNumber off, XLogRecData **prda
btree->curitem++;
}
data.nitem = btree->curitem - savedPos;
- rdata[cnt].len = sizeofitem * data.nitem;
+ rdata[2].len = sizeofitem * data.nitem;
}
else
{
diff --git a/src/backend/access/gin/ginentrypage.c b/src/backend/access/gin/ginentrypage.c
index fa134f9fc3f..97cd755e3ef 100644
--- a/src/backend/access/gin/ginentrypage.c
+++ b/src/backend/access/gin/ginentrypage.c
@@ -487,7 +487,6 @@ entryPlaceToPage(GinBtree btree, Buffer buf, OffsetNumber off, XLogRecData **prd
{
Page page = BufferGetPage(buf);
OffsetNumber placed;
- int cnt = 0;
/* these must be static so they can be returned to caller */
static XLogRecData rdata[3];
@@ -510,32 +509,25 @@ entryPlaceToPage(GinBtree btree, Buffer buf, OffsetNumber off, XLogRecData **prd
data.isLeaf = GinPageIsLeaf(page) ? TRUE : FALSE;
/*
- * Prevent full page write if child's split occurs. That is needed to
- * remove incomplete splits while replaying WAL
- *
- * data.updateBlkno contains new block number (of newly created right
- * page) for recently splited page.
+ * For incomplete-split tracking, we need updateBlkno information and the
+ * inserted item even when we make a full page image of the page, so put
+ * the buffer reference in a separate XLogRecData entry.
*/
- if (data.updateBlkno == InvalidBlockNumber)
- {
- rdata[0].buffer = buf;
- rdata[0].buffer_std = TRUE;
- rdata[0].data = NULL;
- rdata[0].len = 0;
- rdata[0].next = &rdata[1];
- cnt++;
- }
-
- rdata[cnt].buffer = InvalidBuffer;
- rdata[cnt].data = (char *) &data;
- rdata[cnt].len = sizeof(ginxlogInsert);
- rdata[cnt].next = &rdata[cnt + 1];
- cnt++;
+ rdata[0].buffer = buf;
+ rdata[0].buffer_std = TRUE;
+ rdata[0].data = NULL;
+ rdata[0].len = 0;
+ rdata[0].next = &rdata[1];
- rdata[cnt].buffer = InvalidBuffer;
- rdata[cnt].data = (char *) btree->entry;
- rdata[cnt].len = IndexTupleSize(btree->entry);
- rdata[cnt].next = NULL;
+ rdata[1].buffer = InvalidBuffer;
+ rdata[1].data = (char *) &data;
+ rdata[1].len = sizeof(ginxlogInsert);
+ rdata[1].next = &rdata[2];
+
+ rdata[2].buffer = InvalidBuffer;
+ rdata[2].data = (char *) btree->entry;
+ rdata[2].len = IndexTupleSize(btree->entry);
+ rdata[2].next = NULL;
btree->entry = NULL;
}