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

Commit 384cad5

Browse files
committed
Fix two distinct errors in creation of GIN_INSERT_LISTPAGE xlog records.
In practice these mistakes were always masked when full_page_writes was on, because XLogInsert would always choose to log the full page, and then ginRedoInsertListPage wouldn't try to do anything. But with full_page_writes off a WAL replay failure was certain. The GIN_INSERT_LISTPAGE record type could probably be eliminated entirely in favor of using XLOG_HEAP_NEWPAGE, but I refrained from doing that now since it would have required a significantly more invasive patch. In passing do a little bit of code cleanup, including making the accounting for free space on GIN list pages more precise. (This wasn't a bug as the errors were always in the conservative direction.) Per report from Simon. Back-patch to 8.4 which contains the identical code.
1 parent f3ef948 commit 384cad5

File tree

1 file changed

+44
-34
lines changed

1 file changed

+44
-34
lines changed

src/backend/access/gin/ginfast.c

Lines changed: 44 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
* Portions Copyright (c) 1994, Regents of the University of California
1212
*
1313
* IDENTIFICATION
14-
* $PostgreSQL: pgsql/src/backend/access/gin/ginfast.c,v 1.3 2009/06/11 14:48:53 momjian Exp $
14+
* $PostgreSQL: pgsql/src/backend/access/gin/ginfast.c,v 1.4 2009/09/15 20:31:30 tgl Exp $
1515
*
1616
*-------------------------------------------------------------------------
1717
*/
@@ -41,13 +41,15 @@ typedef struct DatumArray
4141

4242
/*
4343
* Build a pending-list page from the given array of tuples, and write it out.
44+
*
45+
* Returns amount of free space left on the page.
4446
*/
4547
static int32
4648
writeListPage(Relation index, Buffer buffer,
4749
IndexTuple *tuples, int32 ntuples, BlockNumber rightlink)
4850
{
4951
Page page = BufferGetPage(buffer);
50-
int i,
52+
int32 i,
5153
freesize,
5254
size = 0;
5355
OffsetNumber l,
@@ -100,8 +102,6 @@ writeListPage(Relation index, Buffer buffer,
100102
GinPageGetOpaque(page)->maxoff = 0;
101103
}
102104

103-
freesize = PageGetFreeSpace(page);
104-
105105
MarkBufferDirty(buffer);
106106

107107
if (!index->rd_istemp)
@@ -110,26 +110,30 @@ writeListPage(Relation index, Buffer buffer,
110110
ginxlogInsertListPage data;
111111
XLogRecPtr recptr;
112112

113-
rdata[0].buffer = buffer;
114-
rdata[0].buffer_std = true;
113+
data.node = index->rd_node;
114+
data.blkno = BufferGetBlockNumber(buffer);
115+
data.rightlink = rightlink;
116+
data.ntuples = ntuples;
117+
118+
rdata[0].buffer = InvalidBuffer;
115119
rdata[0].data = (char *) &data;
116120
rdata[0].len = sizeof(ginxlogInsertListPage);
117121
rdata[0].next = rdata + 1;
118122

119-
rdata[1].buffer = InvalidBuffer;
123+
rdata[1].buffer = buffer;
124+
rdata[1].buffer_std = true;
120125
rdata[1].data = workspace;
121126
rdata[1].len = size;
122127
rdata[1].next = NULL;
123128

124-
data.blkno = BufferGetBlockNumber(buffer);
125-
data.rightlink = rightlink;
126-
data.ntuples = ntuples;
127-
128129
recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_INSERT_LISTPAGE, rdata);
129130
PageSetLSN(page, recptr);
130131
PageSetTLI(page, ThisTimeLineID);
131132
}
132133

134+
/* get free space before releasing buffer */
135+
freesize = PageGetExactFreeSpace(page);
136+
133137
UnlockReleaseBuffer(buffer);
134138

135139
END_CRIT_SECTION();
@@ -165,7 +169,8 @@ makeSublist(Relation index, IndexTuple *tuples, int32 ntuples,
165169
{
166170
res->nPendingPages++;
167171
writeListPage(index, prevBuffer,
168-
tuples + startTuple, i - startTuple,
172+
tuples + startTuple,
173+
i - startTuple,
169174
BufferGetBlockNumber(curBuffer));
170175
}
171176
else
@@ -180,7 +185,7 @@ makeSublist(Relation index, IndexTuple *tuples, int32 ntuples,
180185

181186
tupsize = MAXALIGN(IndexTupleSize(tuples[i])) + sizeof(ItemIdData);
182187

183-
if (size + tupsize >= GinListPageSize)
188+
if (size + tupsize > GinListPageSize)
184189
{
185190
/* won't fit, force a new page and reprocess */
186191
i--;
@@ -197,7 +202,8 @@ makeSublist(Relation index, IndexTuple *tuples, int32 ntuples,
197202
*/
198203
res->tail = BufferGetBlockNumber(curBuffer);
199204
res->tailFreeSize = writeListPage(index, curBuffer,
200-
tuples + startTuple, ntuples - startTuple,
205+
tuples + startTuple,
206+
ntuples - startTuple,
201207
InvalidBlockNumber);
202208
res->nPendingPages++;
203209
/* that was only one heap tuple */
@@ -237,7 +243,7 @@ ginHeapTupleFastInsert(Relation index, GinState *ginstate,
237243
metabuffer = ReadBuffer(index, GIN_METAPAGE_BLKNO);
238244
metapage = BufferGetPage(metabuffer);
239245

240-
if (collector->sumsize + collector->ntuples * sizeof(ItemIdData) > GIN_PAGE_FREESIZE)
246+
if (collector->sumsize + collector->ntuples * sizeof(ItemIdData) > GinListPageSize)
241247
{
242248
/*
243249
* Total size is greater than one page => make sublist
@@ -265,13 +271,12 @@ ginHeapTupleFastInsert(Relation index, GinState *ginstate,
265271

266272
if (separateList)
267273
{
268-
GinMetaPageData sublist;
269-
270274
/*
271275
* We should make sublist separately and append it to the tail
272276
*/
273-
memset(&sublist, 0, sizeof(GinMetaPageData));
277+
GinMetaPageData sublist;
274278

279+
memset(&sublist, 0, sizeof(GinMetaPageData));
275280
makeSublist(index, collector->tuples, collector->ntuples, &sublist);
276281

277282
/*
@@ -283,45 +288,44 @@ ginHeapTupleFastInsert(Relation index, GinState *ginstate,
283288
if (metadata->head == InvalidBlockNumber)
284289
{
285290
/*
286-
* Sublist becomes main list
291+
* Main list is empty, so just copy sublist into main list
287292
*/
288293
START_CRIT_SECTION();
294+
289295
memcpy(metadata, &sublist, sizeof(GinMetaPageData));
290-
memcpy(&data.metadata, &sublist, sizeof(GinMetaPageData));
291296
}
292297
else
293298
{
294299
/*
295-
* merge lists
300+
* Merge lists
296301
*/
297-
298302
data.prevTail = metadata->tail;
303+
data.newRightlink = sublist.head;
304+
299305
buffer = ReadBuffer(index, metadata->tail);
300306
LockBuffer(buffer, GIN_EXCLUSIVE);
301307
page = BufferGetPage(buffer);
308+
302309
Assert(GinPageGetOpaque(page)->rightlink == InvalidBlockNumber);
303310

304311
START_CRIT_SECTION();
305312

306313
GinPageGetOpaque(page)->rightlink = sublist.head;
314+
315+
MarkBufferDirty(buffer);
316+
307317
metadata->tail = sublist.tail;
308318
metadata->tailFreeSize = sublist.tailFreeSize;
309319

310320
metadata->nPendingPages += sublist.nPendingPages;
311321
metadata->nPendingHeapTuples += sublist.nPendingHeapTuples;
312-
313-
memcpy(&data.metadata, metadata, sizeof(GinMetaPageData));
314-
data.newRightlink = sublist.head;
315-
316-
MarkBufferDirty(buffer);
317322
}
318323
}
319324
else
320325
{
321326
/*
322-
* Insert into tail page, metapage is already locked
327+
* Insert into tail page. Metapage is already locked
323328
*/
324-
325329
OffsetNumber l,
326330
off;
327331
int i,
@@ -331,6 +335,7 @@ ginHeapTupleFastInsert(Relation index, GinState *ginstate,
331335
buffer = ReadBuffer(index, metadata->tail);
332336
LockBuffer(buffer, GIN_EXCLUSIVE);
333337
page = BufferGetPage(buffer);
338+
334339
off = (PageIsEmpty(page)) ? FirstOffsetNumber :
335340
OffsetNumberNext(PageGetMaxOffsetNumber(page));
336341

@@ -368,20 +373,24 @@ ginHeapTupleFastInsert(Relation index, GinState *ginstate,
368373
off++;
369374
}
370375

371-
metadata->tailFreeSize -= collector->sumsize + collector->ntuples * sizeof(ItemIdData);
372-
memcpy(&data.metadata, metadata, sizeof(GinMetaPageData));
376+
Assert((ptr - rdata[1].data) <= collector->sumsize);
377+
378+
metadata->tailFreeSize = PageGetExactFreeSpace(page);
379+
373380
MarkBufferDirty(buffer);
374381
}
375382

376383
/*
377-
* Make real write
384+
* Write metabuffer, make xlog entry
378385
*/
379-
380386
MarkBufferDirty(metabuffer);
387+
381388
if (!index->rd_istemp)
382389
{
383390
XLogRecPtr recptr;
384391

392+
memcpy(&data.metadata, metadata, sizeof(GinMetaPageData));
393+
385394
recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_UPDATE_META_PAGE, rdata);
386395
PageSetLSN(metapage, recptr);
387396
PageSetTLI(metapage, ThisTimeLineID);
@@ -552,7 +561,6 @@ shiftList(Relation index, Buffer metabuffer, BlockNumber newHead,
552561
metadata->nPendingPages = 0;
553562
metadata->nPendingHeapTuples = 0;
554563
}
555-
memcpy(&data.metadata, metadata, sizeof(GinMetaPageData));
556564

557565
MarkBufferDirty(metabuffer);
558566

@@ -567,6 +575,8 @@ shiftList(Relation index, Buffer metabuffer, BlockNumber newHead,
567575
{
568576
XLogRecPtr recptr;
569577

578+
memcpy(&data.metadata, metadata, sizeof(GinMetaPageData));
579+
570580
recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_DELETE_LISTPAGE, rdata);
571581
PageSetLSN(metapage, recptr);
572582
PageSetTLI(metapage, ThisTimeLineID);

0 commit comments

Comments
 (0)