postgres.git / summary / log / commit / refs
commit feb4e218e5f9d8ec2d0c6f2eac28ad786ea9d79c
Author: Amit Kapila <akapila@postgresql.org>
Date: Tue Sep 12 04:06:56 2023 +0000
First released in: 11.22, 12.17, 13.13, 14.10, 15.5
Fix uninitialized access to InitialRunningXacts during decoding after ERROR.
The transactions and subtransactions array that was allocated under
snapshot builder memory context and recorded during decoding was not
cleared in case of errors. This can result in an assertion failure if we
attempt to retry logical decoding within the same session. To address this
issue, we register a callback function under the snapshot builder memory
context to clear the recorded transactions and subtransactions array along
with the context.
This problem doesn't exist in PG16 and HEAD as instead of using
InitialRunningXacts, we added the list of transaction IDs and
sub-transaction IDs, that have modified catalogs and are running during
snapshot serialization, to the serialized snapshot (see commit 7f13ac8123).
Author: Hou Zhijie
Reviewed-by: Amit Kapila
Backpatch-through: 11
Discussion: http://postgr.es/m/18055-ab3beed9f4b7b7d6@postgresql.org
src/backend/replication/logical/snapbuild.c | 20 ++++++++++++++++----
1 file changed, 16 insertions(+), 4 deletions(-)
diff --git a/src/backend/replication/logical/snapbuild.c b/src/backend/replication/logical/snapbuild.c
index 02d73e5c939..e32ed39e282 100644
--- a/src/backend/replication/logical/snapbuild.c
+++ b/src/backend/replication/logical/snapbuild.c
@@ -336,6 +336,17 @@ SnapBuildStartNextPhaseAt(SnapBuild *builder, TransactionId at)
builder->was_running.was_xmax = at;
}
+/*
+ * Memory context reset callback for clearing the array of running transactions
+ * and subtransactions.
+ */
+static void
+SnapBuildResetRunningXactsCallback(void *arg)
+{
+ NInitialRunningXacts = 0;
+ InitialRunningXacts = NULL;
+}
+
/*
* Allocate a new snapshot builder.
*
@@ -351,6 +362,7 @@ AllocateSnapshotBuilder(ReorderBuffer *reorder,
MemoryContext context;
MemoryContext oldcontext;
SnapBuild *builder;
+ MemoryContextCallback *mcallback;
/* allocate memory in own context, to have better accountability */
context = AllocSetContextCreate(CurrentMemoryContext,
@@ -375,6 +387,10 @@ AllocateSnapshotBuilder(ReorderBuffer *reorder,
builder->start_decoding_at = start_lsn;
builder->building_full_snapshot = need_full_snapshot;
+ mcallback = palloc0(sizeof(MemoryContextCallback));
+ mcallback->func = SnapBuildResetRunningXactsCallback;
+ MemoryContextRegisterResetCallback(CurrentMemoryContext, mcallback);
+
MemoryContextSwitchTo(oldcontext);
/* The initial running transactions array must be empty. */
@@ -400,10 +416,6 @@ FreeSnapshotBuilder(SnapBuild *builder)
/* other resources are deallocated via memory context reset */
MemoryContextDelete(context);
-
- /* InitialRunningXacts is freed along with the context */
- NInitialRunningXacts = 0;
- InitialRunningXacts = NULL;
}
/*
[parent: 0aeadb4f7974]