Skip to content

Commit acbffaa

Browse files
committed
The GiST scan algorithm uses LSNs to detect concurrent pages splits, but
temporary indexes are not WAL-logged. We used a constant LSN for temporary indexes, on the assumption that we don't need to worry about concurrent page splits in temporary indexes because they're only visible to the current session. But that assumption is wrong, it's possible to insert rows and split pages in the same session, while a scan is in progress. For example, by opening a cursor and fetching some rows, and INSERTing new rows before fetching some more. Fix by generating fake increasing LSNs, used in place of real LSNs in temporary GiST indexes.
1 parent 0e27a73 commit acbffaa

File tree

4 files changed

+30
-10
lines changed

4 files changed

+30
-10
lines changed

src/backend/access/gist/gist.c

+4-6
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,6 @@
2323
#include "miscadmin.h"
2424
#include "utils/memutils.h"
2525

26-
const XLogRecPtr XLogRecPtrForTemp = {1, 1};
27-
2826
/* Working state for gistbuild and its callback */
2927
typedef struct
3028
{
@@ -127,7 +125,7 @@ gistbuild(PG_FUNCTION_ARGS)
127125
END_CRIT_SECTION();
128126
}
129127
else
130-
PageSetLSN(BufferGetPage(buffer), XLogRecPtrForTemp);
128+
PageSetLSN(BufferGetPage(buffer), GetXLogRecPtrForTemp());
131129
LockBuffer(buffer, GIST_UNLOCK);
132130
WriteBuffer(buffer);
133131

@@ -356,7 +354,7 @@ gistplacetopage(GISTInsertState *state, GISTSTATE *giststate)
356354
ptr = dist;
357355
while (ptr)
358356
{
359-
PageSetLSN(BufferGetPage(ptr->buffer), XLogRecPtrForTemp);
357+
PageSetLSN(BufferGetPage(ptr->buffer), GetXLogRecPtrForTemp());
360358
ptr = ptr->next;
361359
}
362360
}
@@ -475,7 +473,7 @@ gistplacetopage(GISTInsertState *state, GISTSTATE *giststate)
475473
END_CRIT_SECTION();
476474
}
477475
else
478-
PageSetLSN(state->stack->page, XLogRecPtrForTemp);
476+
PageSetLSN(state->stack->page, GetXLogRecPtrForTemp());
479477

480478
if (state->stack->blkno == GIST_ROOT_BLKNO)
481479
state->needInsertComplete = false;
@@ -1206,7 +1204,7 @@ gistnewroot(Relation r, Buffer buffer, IndexTuple *itup, int len, ItemPointer ke
12061204
END_CRIT_SECTION();
12071205
}
12081206
else
1209-
PageSetLSN(page, XLogRecPtrForTemp);
1207+
PageSetLSN(page, GetXLogRecPtrForTemp());
12101208
}
12111209

12121210
void

src/backend/access/gist/gistutil.c

+21
Original file line numberDiff line numberDiff line change
@@ -977,3 +977,24 @@ gistNewBuffer(Relation r)
977977

978978
return buffer;
979979
}
980+
981+
/*
982+
* Temporary GiST indexes are not WAL-logged, but we need LSNs to detect
983+
* concurrent page splits anyway. GetXLogRecPtrForTemp() provides a fake
984+
* sequence of LSNs for that purpose. Each call generates an LSN that is
985+
* greater than any previous value returned by this function in the same
986+
* session.
987+
*/
988+
XLogRecPtr
989+
GetXLogRecPtrForTemp(void)
990+
{
991+
static XLogRecPtr counter = {0, 1};
992+
993+
counter.xrecoff++;
994+
if (counter.xrecoff == 0)
995+
{
996+
counter.xlogid++;
997+
counter.xrecoff++;
998+
}
999+
return counter;
1000+
}

src/backend/access/gist/gistvacuum.c

+3-3
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ gistVacuumUpdate(GistVacuum *gv, BlockNumber blkno, bool needunion)
201201
ptr = dist;
202202
while (ptr)
203203
{
204-
PageSetLSN(BufferGetPage(ptr->buffer), XLogRecPtrForTemp);
204+
PageSetLSN(BufferGetPage(ptr->buffer), GetXLogRecPtrForTemp());
205205
ptr = ptr->next;
206206
}
207207
}
@@ -306,7 +306,7 @@ gistVacuumUpdate(GistVacuum *gv, BlockNumber blkno, bool needunion)
306306
pfree(rdata);
307307
}
308308
else
309-
PageSetLSN(page, XLogRecPtrForTemp);
309+
PageSetLSN(page, GetXLogRecPtrForTemp());
310310
WriteBuffer(buffer);
311311
}
312312
else
@@ -589,7 +589,7 @@ gistbulkdelete(PG_FUNCTION_ARGS)
589589
pfree(rdata);
590590
}
591591
else
592-
PageSetLSN(page, XLogRecPtrForTemp);
592+
PageSetLSN(page, GetXLogRecPtrForTemp());
593593
WriteNoReleaseBuffer(buffer);
594594
}
595595
}

src/include/access/gist_private.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,6 @@ typedef struct GISTScanOpaqueData
9191
typedef GISTScanOpaqueData *GISTScanOpaque;
9292

9393
/* XLog stuff */
94-
extern const XLogRecPtr XLogRecPtrForTemp;
9594

9695
#define XLOG_GIST_ENTRY_UPDATE 0x00
9796
#define XLOG_GIST_ENTRY_DELETE 0x10
@@ -318,6 +317,8 @@ extern void gistdentryinit(GISTSTATE *giststate, int nkey, GISTENTRY *e,
318317
void gistUserPicksplit(Relation r, GistEntryVector *entryvec, GIST_SPLITVEC *v,
319318
IndexTuple *itup, int len, GISTSTATE *giststate);
320319

320+
extern XLogRecPtr GetXLogRecPtrForTemp(void);
321+
321322
/* gistvacuum.c */
322323
extern Datum gistbulkdelete(PG_FUNCTION_ARGS);
323324
extern Datum gistvacuumcleanup(PG_FUNCTION_ARGS);

0 commit comments

Comments
 (0)