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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy