v20240730-0002-atomic-LSN-counter.patch
text/x-patch
Filename: v20240730-0002-atomic-LSN-counter.patch
Type: text/x-patch
Part: 1
Message:
Re: WIP: parallel GiST index builds
Patch
Format: format-patch
Series: patch v20240730-0002
Subject: atomic LSN counter
| File | + | − |
|---|---|---|
| src/backend/access/gist/gistbuild.c | 15 | 4 |
| src/backend/access/gist/gist.c | 12 | 12 |
| src/backend/access/gist/gistutil.c | 3 | 7 |
| src/backend/access/gist/gistvacuum.c | 3 | 3 |
| src/include/access/gist_private.h | 4 | 4 |
From a2f606d5dba1d7902f925a1c9af95cd27ade7488 Mon Sep 17 00:00:00 2001
From: Tomas Vondra <tomas@2ndquadrant.com>
Date: Mon, 29 Jul 2024 18:03:44 +0200
Subject: [PATCH v20240730 2/6] atomic LSN counter
---
src/backend/access/gist/gist.c | 24 ++++++++++++------------
src/backend/access/gist/gistbuild.c | 19 +++++++++++++++----
src/backend/access/gist/gistutil.c | 10 +++-------
src/backend/access/gist/gistvacuum.c | 6 +++---
src/include/access/gist_private.h | 8 ++++----
5 files changed, 37 insertions(+), 30 deletions(-)
diff --git a/src/backend/access/gist/gist.c b/src/backend/access/gist/gist.c
index f5f56fb2503..63d5580120d 100644
--- a/src/backend/access/gist/gist.c
+++ b/src/backend/access/gist/gist.c
@@ -182,7 +182,7 @@ gistinsert(Relation r, Datum *values, bool *isnull,
values, isnull, true /* size is currently bogus */ );
itup->t_tid = *ht_ctid;
- gistdoinsert(r, itup, 0, giststate, heapRel, false, false);
+ gistdoinsert(r, itup, 0, giststate, heapRel, false, NULL);
/* cleanup */
MemoryContextSwitchTo(oldCxt);
@@ -231,7 +231,7 @@ gistplacetopage(Relation rel, Size freespace, GISTSTATE *giststate,
bool markfollowright,
Relation heapRel,
bool is_build,
- bool is_parallel)
+ pg_atomic_uint64 *fakelsn)
{
BlockNumber blkno = BufferGetBlockNumber(buffer);
Page page = BufferGetPage(buffer);
@@ -508,8 +508,8 @@ gistplacetopage(Relation rel, Size freespace, GISTSTATE *giststate,
*/
if (is_build)
{
- if (is_parallel)
- recptr = gistGetFakeLSN(rel, is_parallel);
+ if (fakelsn)
+ recptr = pg_atomic_fetch_add_u64(fakelsn, 1);
else
recptr = GistBuildLSN;
}
@@ -520,7 +520,7 @@ gistplacetopage(Relation rel, Size freespace, GISTSTATE *giststate,
dist, oldrlink, oldnsn, leftchildbuf,
markfollowright);
else
- recptr = gistGetFakeLSN(rel, false);
+ recptr = gistGetFakeLSN(rel);
}
for (ptr = dist; ptr; ptr = ptr->next)
@@ -580,8 +580,8 @@ gistplacetopage(Relation rel, Size freespace, GISTSTATE *giststate,
if (is_build)
{
- if (is_parallel)
- recptr = gistGetFakeLSN(rel, is_parallel);
+ if (fakelsn)
+ recptr = pg_atomic_fetch_add_u64(fakelsn, 1);
else
recptr = GistBuildLSN;
}
@@ -603,7 +603,7 @@ gistplacetopage(Relation rel, Size freespace, GISTSTATE *giststate,
leftchildbuf);
}
else
- recptr = gistGetFakeLSN(rel, false);
+ recptr = gistGetFakeLSN(rel);
}
PageSetLSN(page, recptr);
@@ -647,7 +647,7 @@ gistplacetopage(Relation rel, Size freespace, GISTSTATE *giststate,
void
gistdoinsert(Relation r, IndexTuple itup, Size freespace,
GISTSTATE *giststate, Relation heapRel, bool is_build,
- bool is_parallel)
+ pg_atomic_uint64 *fakelsn)
{
ItemId iid;
IndexTuple idxtuple;
@@ -661,7 +661,7 @@ gistdoinsert(Relation r, IndexTuple itup, Size freespace,
state.r = r;
state.heapRel = heapRel;
state.is_build = is_build;
- state.is_parallel = is_parallel;
+ state.fakelsn = fakelsn;
/* Start from the root */
firststack.blkno = GIST_ROOT_BLKNO;
@@ -1320,7 +1320,7 @@ gistinserttuples(GISTInsertState *state, GISTInsertStack *stack,
true,
state->heapRel,
state->is_build,
- state->is_parallel);
+ state->fakelsn);
/*
* Before recursing up in case the page was split, release locks on the
@@ -1739,7 +1739,7 @@ gistprunepage(Relation rel, Page page, Buffer buffer, Relation heapRel)
PageSetLSN(page, recptr);
}
else
- PageSetLSN(page, gistGetFakeLSN(rel, false));
+ PageSetLSN(page, gistGetFakeLSN(rel));
END_CRIT_SECTION();
}
diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c
index c8fa67beebb..c7ac2487cda 100644
--- a/src/backend/access/gist/gistbuild.c
+++ b/src/backend/access/gist/gistbuild.c
@@ -140,6 +140,9 @@ typedef struct GISTShared
double reltuples;
double indtuples;
+ /* Used to generate LSNs during parallel build. */
+ pg_atomic_uint64 parallelLSN;
+
/*
* ParallelTableScanDescData data follows. Can't directly embed here, as
* implementations of the parallel table scan desc interface might need
@@ -217,6 +220,7 @@ typedef struct
*/
bool is_parallel;
GISTLeader *gist_leader;
+ pg_atomic_uint64 *fakelsn;
/*
* Extra data structures used during a sorting build.
@@ -1043,7 +1047,7 @@ gistBuildCallback(Relation index,
* locked, we call gistdoinsert directly.
*/
gistdoinsert(index, itup, buildstate->freespace,
- buildstate->giststate, buildstate->heaprel, true, false);
+ buildstate->giststate, buildstate->heaprel, true, NULL);
}
MemoryContextSwitchTo(oldCtx);
@@ -1098,6 +1102,7 @@ gistBuildParallelCallback(Relation index,
void *state)
{
GISTBuildState *buildstate = (GISTBuildState *) state;
+
IndexTuple itup;
MemoryContext oldCtx;
@@ -1118,7 +1123,8 @@ gistBuildParallelCallback(Relation index,
* locked, we call gistdoinsert directly.
*/
gistdoinsert(index, itup, buildstate->freespace,
- buildstate->giststate, buildstate->heaprel, true, true);
+ buildstate->giststate, buildstate->heaprel, true,
+ buildstate->fakelsn);
MemoryContextSwitchTo(oldCtx);
MemoryContextReset(buildstate->giststate->tempCxt);
@@ -1292,8 +1298,7 @@ gistbufferinginserttuples(GISTBuildState *buildstate, Buffer buffer, int level,
InvalidBuffer,
&splitinfo,
false,
- buildstate->heaprel, true,
- buildstate->is_parallel);
+ buildstate->heaprel, true, NULL);
/*
* If this is a root split, update the root path item kept in memory. This
@@ -1925,6 +1930,9 @@ _gist_begin_parallel(GISTBuildState *buildstate, Relation heap, Relation index,
gistshared->reltuples = 0.0;
gistshared->indtuples = 0.0;
+ /* initialize the counter used to generate fake LSNs */
+ pg_atomic_init_u64(&gistshared->parallelLSN, 1);
+
table_parallelscan_initialize(heap,
ParallelTableScanFromGistShared(gistshared),
snapshot);
@@ -1974,6 +1982,7 @@ _gist_begin_parallel(GISTBuildState *buildstate, Relation heap, Relation index,
/* Save leader state now that it's clear build will be parallel */
buildstate->is_parallel = true;
buildstate->gist_leader = gistleader;
+ buildstate->fakelsn = &gistshared->parallelLSN;
/* Join heap scan ourselves */
if (leaderparticipates)
@@ -2202,6 +2211,8 @@ _gist_parallel_build_main(dsm_segment *seg, shm_toc *toc)
buildstate.is_parallel = true;
buildstate.gist_leader = NULL;
+ buildstate.fakelsn = &gistshared->parallelLSN;
+
/*
* Create a temporary memory context that is reset once for each tuple
* processed. (Note: we don't bother to make this a child of the
diff --git a/src/backend/access/gist/gistutil.c b/src/backend/access/gist/gistutil.c
index 733d5849317..78e98d68b15 100644
--- a/src/backend/access/gist/gistutil.c
+++ b/src/backend/access/gist/gistutil.c
@@ -1012,7 +1012,7 @@ gistproperty(Oid index_oid, int attno,
* purpose.
*/
XLogRecPtr
-gistGetFakeLSN(Relation rel, bool is_parallel)
+gistGetFakeLSN(Relation rel)
{
if (rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP)
{
@@ -1035,12 +1035,8 @@ gistGetFakeLSN(Relation rel, bool is_parallel)
static XLogRecPtr lastlsn = InvalidXLogRecPtr;
XLogRecPtr currlsn = GetXLogInsertRecPtr();
- /*
- * Shouldn't be called for WAL-logging relations, but parallell
- * builds are an exception - we need the fake LSN to detect
- * concurrent changes.
- */
- Assert(is_parallel || !RelationNeedsWAL(rel));
+ /* Shouldn't be called for WAL-logging relations */
+ Assert(!RelationNeedsWAL(rel));
/* No need for an actual record if we already have a distinct LSN */
if (!XLogRecPtrIsInvalid(lastlsn) && lastlsn == currlsn)
diff --git a/src/backend/access/gist/gistvacuum.c b/src/backend/access/gist/gistvacuum.c
index 082804e9c7d..24fb94f473e 100644
--- a/src/backend/access/gist/gistvacuum.c
+++ b/src/backend/access/gist/gistvacuum.c
@@ -181,7 +181,7 @@ gistvacuumscan(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
if (RelationNeedsWAL(rel))
vstate.startNSN = GetInsertRecPtr();
else
- vstate.startNSN = gistGetFakeLSN(rel, false);
+ vstate.startNSN = gistGetFakeLSN(rel);
/*
* The outer loop iterates over all index pages, in physical order (we
@@ -376,7 +376,7 @@ restart:
PageSetLSN(page, recptr);
}
else
- PageSetLSN(page, gistGetFakeLSN(rel, false));
+ PageSetLSN(page, gistGetFakeLSN(rel));
END_CRIT_SECTION();
@@ -664,7 +664,7 @@ gistdeletepage(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
if (RelationNeedsWAL(info->index))
recptr = gistXLogPageDelete(leafBuffer, txid, parentBuffer, downlink);
else
- recptr = gistGetFakeLSN(info->index, false);
+ recptr = gistGetFakeLSN(info->index);
PageSetLSN(parentPage, recptr);
PageSetLSN(leafPage, recptr);
diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h
index d5b22bc1018..09f535ff56e 100644
--- a/src/include/access/gist_private.h
+++ b/src/include/access/gist_private.h
@@ -255,7 +255,7 @@ typedef struct
Relation heapRel;
Size freespace; /* free space to be left */
bool is_build;
- bool is_parallel;
+ pg_atomic_uint64 *fakelsn;
GISTInsertStack *stack;
} GISTInsertState;
@@ -416,7 +416,7 @@ extern void gistdoinsert(Relation r,
GISTSTATE *giststate,
Relation heapRel,
bool is_build,
- bool is_parallel);
+ pg_atomic_uint64 *fakelsn);
/* A List of these is returned from gistplacetopage() in *splitinfo */
typedef struct
@@ -434,7 +434,7 @@ extern bool gistplacetopage(Relation rel, Size freespace, GISTSTATE *giststate,
bool markfollowright,
Relation heapRel,
bool is_build,
- bool is_parallel);
+ pg_atomic_uint64 *fakelsn);
extern SplitPageLayout *gistSplit(Relation r, Page page, IndexTuple *itup,
int len, GISTSTATE *giststate);
@@ -535,7 +535,7 @@ extern void gistMakeUnionKey(GISTSTATE *giststate, int attno,
GISTENTRY *entry2, bool isnull2,
Datum *dst, bool *dstisnull);
-extern XLogRecPtr gistGetFakeLSN(Relation rel, bool is_parallel);
+extern XLogRecPtr gistGetFakeLSN(Relation rel);
/* gistvacuum.c */
extern IndexBulkDeleteResult *gistbulkdelete(IndexVacuumInfo *info,
--
2.45.2