Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit bf5ccf3

Browse files
committed
- Add check of already changed page while replay WAL. This touches only
ginRedoInsert(), because other ginRedo* functions rewrite whole page or make changes which could be applied several times without consistent's loss - Remove check of identifying of corresponding split record: it's possible that replaying of WAL starts after actual page split, but before removing of that split from incomplete splits list. In this case, that check cause FATAL error. Per stress test which reproduces bug reported by Craig McElroy <craig.mcelroy@contegix.com>
1 parent f7967d4 commit bf5ccf3

File tree

1 file changed

+60
-52
lines changed

1 file changed

+60
-52
lines changed

src/backend/access/gin/ginxlog.c

Lines changed: 60 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/access/gin/ginxlog.c,v 1.9 2007/09/20 17:56:30 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/access/gin/ginxlog.c,v 1.10 2007/10/29 19:26:57 teodor Exp $
1212
*-------------------------------------------------------------------------
1313
*/
1414
#include "postgres.h"
@@ -53,7 +53,6 @@ static void
5353
forgetIncompleteSplit(RelFileNode node, BlockNumber leftBlkno, BlockNumber updateBlkno)
5454
{
5555
ListCell *l;
56-
bool found = false;
5756

5857
foreach(l, incomplete_splits)
5958
{
@@ -62,16 +61,9 @@ forgetIncompleteSplit(RelFileNode node, BlockNumber leftBlkno, BlockNumber updat
6261
if (RelFileNodeEquals(node, split->node) && leftBlkno == split->leftBlkno && updateBlkno == split->rightBlkno)
6362
{
6463
incomplete_splits = list_delete_ptr(incomplete_splits, split);
65-
found = true;
6664
break;
6765
}
6866
}
69-
70-
if (!found)
71-
{
72-
elog(ERROR, "failed to identify corresponding split record for %u/%u/%u",
73-
node.relNode, leftBlkno, updateBlkno);
74-
}
7567
}
7668

7769
static void
@@ -129,7 +121,7 @@ ginRedoInsert(XLogRecPtr lsn, XLogRecord *record)
129121
Buffer buffer;
130122
Page page;
131123

132-
/* nothing else to do if page was backed up (and no info to do it with) */
124+
/* nothing else to do if page was backed up */
133125
if (record->xl_info & XLR_BKP_BLOCK_1)
134126
return;
135127

@@ -143,74 +135,90 @@ ginRedoInsert(XLogRecPtr lsn, XLogRecord *record)
143135
Assert(data->isDelete == FALSE);
144136
Assert(GinPageIsData(page));
145137

146-
if (data->isLeaf)
138+
if ( ! XLByteLE(lsn, PageGetLSN(page)) )
147139
{
148-
OffsetNumber i;
149-
ItemPointerData *items = (ItemPointerData *) (XLogRecGetData(record) + sizeof(ginxlogInsert));
140+
if (data->isLeaf)
141+
{
142+
OffsetNumber i;
143+
ItemPointerData *items = (ItemPointerData *) (XLogRecGetData(record) + sizeof(ginxlogInsert));
150144

151-
Assert(GinPageIsLeaf(page));
152-
Assert(data->updateBlkno == InvalidBlockNumber);
145+
Assert(GinPageIsLeaf(page));
146+
Assert(data->updateBlkno == InvalidBlockNumber);
153147

154-
for (i = 0; i < data->nitem; i++)
155-
GinDataPageAddItem(page, items + i, data->offset + i);
156-
}
157-
else
158-
{
159-
PostingItem *pitem;
148+
for (i = 0; i < data->nitem; i++)
149+
GinDataPageAddItem(page, items + i, data->offset + i);
150+
}
151+
else
152+
{
153+
PostingItem *pitem;
160154

161-
Assert(!GinPageIsLeaf(page));
155+
Assert(!GinPageIsLeaf(page));
162156

163-
if (data->updateBlkno != InvalidBlockNumber)
164-
{
165-
/* update link to right page after split */
166-
pitem = (PostingItem *) GinDataPageGetItem(page, data->offset);
167-
PostingItemSetBlockNumber(pitem, data->updateBlkno);
168-
}
157+
if (data->updateBlkno != InvalidBlockNumber)
158+
{
159+
/* update link to right page after split */
160+
pitem = (PostingItem *) GinDataPageGetItem(page, data->offset);
161+
PostingItemSetBlockNumber(pitem, data->updateBlkno);
162+
}
169163

170-
pitem = (PostingItem *) (XLogRecGetData(record) + sizeof(ginxlogInsert));
164+
pitem = (PostingItem *) (XLogRecGetData(record) + sizeof(ginxlogInsert));
171165

172-
GinDataPageAddItem(page, pitem, data->offset);
166+
GinDataPageAddItem(page, pitem, data->offset);
167+
}
168+
}
173169

174-
if (data->updateBlkno != InvalidBlockNumber)
175-
forgetIncompleteSplit(data->node, PostingItemGetBlockNumber(pitem), data->updateBlkno);
170+
if (!data->isLeaf && data->updateBlkno != InvalidBlockNumber)
171+
{
172+
PostingItem *pitem = (PostingItem *) (XLogRecGetData(record) + sizeof(ginxlogInsert));
173+
forgetIncompleteSplit(data->node, PostingItemGetBlockNumber(pitem), data->updateBlkno);
176174
}
175+
177176
}
178177
else
179178
{
180179
IndexTuple itup;
181180

182181
Assert(!GinPageIsData(page));
183182

184-
if (data->updateBlkno != InvalidBlockNumber)
183+
if ( ! XLByteLE(lsn, PageGetLSN(page)) )
185184
{
186-
/* update link to right page after split */
187-
Assert(!GinPageIsLeaf(page));
188-
Assert(data->offset >= FirstOffsetNumber && data->offset <= PageGetMaxOffsetNumber(page));
189-
itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, data->offset));
190-
ItemPointerSet(&itup->t_tid, data->updateBlkno, InvalidOffsetNumber);
191-
}
185+
if (data->updateBlkno != InvalidBlockNumber)
186+
{
187+
/* update link to right page after split */
188+
Assert(!GinPageIsLeaf(page));
189+
Assert(data->offset >= FirstOffsetNumber && data->offset <= PageGetMaxOffsetNumber(page));
190+
itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, data->offset));
191+
ItemPointerSet(&itup->t_tid, data->updateBlkno, InvalidOffsetNumber);
192+
}
192193

193-
if (data->isDelete)
194-
{
195-
Assert(GinPageIsLeaf(page));
196-
Assert(data->offset >= FirstOffsetNumber && data->offset <= PageGetMaxOffsetNumber(page));
197-
PageIndexTupleDelete(page, data->offset);
198-
}
194+
if (data->isDelete)
195+
{
196+
Assert(GinPageIsLeaf(page));
197+
Assert(data->offset >= FirstOffsetNumber && data->offset <= PageGetMaxOffsetNumber(page));
198+
PageIndexTupleDelete(page, data->offset);
199+
}
199200

200-
itup = (IndexTuple) (XLogRecGetData(record) + sizeof(ginxlogInsert));
201+
itup = (IndexTuple) (XLogRecGetData(record) + sizeof(ginxlogInsert));
201202

202-
if (PageAddItem(page, (Item) itup, IndexTupleSize(itup), data->offset, false, false) == InvalidOffsetNumber)
203-
elog(ERROR, "failed to add item to index page in %u/%u/%u",
204-
data->node.spcNode, data->node.dbNode, data->node.relNode);
203+
if (PageAddItem(page, (Item) itup, IndexTupleSize(itup), data->offset, false, false) == InvalidOffsetNumber)
204+
elog(ERROR, "failed to add item to index page in %u/%u/%u",
205+
data->node.spcNode, data->node.dbNode, data->node.relNode);
206+
}
205207

206208
if (!data->isLeaf && data->updateBlkno != InvalidBlockNumber)
209+
{
210+
itup = (IndexTuple) (XLogRecGetData(record) + sizeof(ginxlogInsert));
207211
forgetIncompleteSplit(data->node, GinItemPointerGetBlockNumber(&itup->t_tid), data->updateBlkno);
212+
}
208213
}
209214

210-
PageSetLSN(page, lsn);
211-
PageSetTLI(page, ThisTimeLineID);
215+
if ( ! XLByteLE(lsn, PageGetLSN(page)) )
216+
{
217+
PageSetLSN(page, lsn);
218+
PageSetTLI(page, ThisTimeLineID);
212219

213-
MarkBufferDirty(buffer);
220+
MarkBufferDirty(buffer);
221+
}
214222
UnlockReleaseBuffer(buffer);
215223
}
216224

0 commit comments

Comments
 (0)