diff options
author | Masahiko Sawada <msawada@postgresql.org> | 2024-07-11 22:48:08 +0900 |
---|---|---|
committer | Masahiko Sawada <msawada@postgresql.org> | 2024-07-11 22:48:08 +0900 |
commit | 1b370758770c3259f2ec09eefe47274be995792e (patch) | |
tree | ed9c4538f132437e84c16d4b38107db326846df9 /src | |
parent | a134baea7ab0cc907b9d9d3d16f9ac97ec8200be (diff) | |
download | postgresql-1b370758770c3259f2ec09eefe47274be995792e.tar.gz postgresql-1b370758770c3259f2ec09eefe47274be995792e.zip |
Fix possibility of logical decoding partial transaction changes.
When creating and initializing a logical slot, the restart_lsn is set
to the latest WAL insertion point (or the latest replay point on
standbys). Subsequently, WAL records are decoded from that point to
find the start point for extracting changes in the
DecodingContextFindStartpoint() function. Since the initial
restart_lsn could be in the middle of a transaction, the start point
must be a consistent point where we won't see the data for partial
transactions.
Previously, when not building a full snapshot, serialized snapshots
were restored, and the SnapBuild jumps to the consistent state even
while finding the start point. Consequently, the slot's restart_lsn
and confirmed_flush could be set to the middle of a transaction. This
could lead to various unexpected consequences. Specifically, there
were reports of logical decoding decoding partial transactions, and
assertion failures occurred because only subtransactions were decoded
without decoding their top-level transaction until decoding the commit
record.
To resolve this issue, the changes prevent restoring the serialized
snapshot and jumping to the consistent state while finding the start
point.
On v17 and HEAD, a flag indicating whether snapshot restores should be
skipped has been added to the SnapBuild struct, and SNAPBUILD_VERSION
has been bumpded.
On backbranches, the flag is stored in the LogicalDecodingContext
instead, preserving on-disk compatibility.
Backpatch to all supported versions.
Reported-by: Drew Callahan
Reviewed-by: Amit Kapila, Hayato Kuroda
Discussion: https://postgr.es/m/2444AA15-D21B-4CCE-8052-52C7C2DAFE5C%40amazon.com
Backpatch-through: 12
Diffstat (limited to 'src')
-rw-r--r-- | src/backend/replication/logical/logical.c | 7 | ||||
-rw-r--r-- | src/backend/replication/logical/snapbuild.c | 19 | ||||
-rw-r--r-- | src/include/replication/logical.h | 6 |
3 files changed, 25 insertions, 7 deletions
diff --git a/src/backend/replication/logical/logical.c b/src/backend/replication/logical/logical.c index 8b79d670012..e6423b955b9 100644 --- a/src/backend/replication/logical/logical.c +++ b/src/backend/replication/logical/logical.c @@ -123,6 +123,7 @@ StartupDecodingContext(List *output_plugin_options, TransactionId xmin_horizon, bool need_full_snapshot, bool fast_forward, + bool in_create, XLogPageReadCB read_page, LogicalOutputPluginWriterPrepareWrite prepare_write, LogicalOutputPluginWriterWrite do_write, @@ -201,6 +202,8 @@ StartupDecodingContext(List *output_plugin_options, ctx->fast_forward = fast_forward; + ctx->in_create = in_create; + MemoryContextSwitchTo(old_context); return ctx; @@ -329,7 +332,7 @@ CreateInitDecodingContext(char *plugin, ReplicationSlotSave(); ctx = StartupDecodingContext(NIL, restart_lsn, xmin_horizon, - need_full_snapshot, false, + need_full_snapshot, false, true, read_page, prepare_write, do_write, update_progress); @@ -428,7 +431,7 @@ CreateDecodingContext(XLogRecPtr start_lsn, ctx = StartupDecodingContext(output_plugin_options, start_lsn, InvalidTransactionId, false, - fast_forward, read_page, prepare_write, + fast_forward, false, read_page, prepare_write, do_write, update_progress); /* call output plugin initialization callback */ diff --git a/src/backend/replication/logical/snapbuild.c b/src/backend/replication/logical/snapbuild.c index bdfd1f02281..517fb4d6c02 100644 --- a/src/backend/replication/logical/snapbuild.c +++ b/src/backend/replication/logical/snapbuild.c @@ -1312,6 +1312,8 @@ SnapBuildProcessRunningXacts(SnapBuild *builder, XLogRecPtr lsn, xl_running_xact static bool SnapBuildFindSnapshot(SnapBuild *builder, XLogRecPtr lsn, xl_running_xacts *running) { + LogicalDecodingContext *ctx = (LogicalDecodingContext *) builder->reorder->private_data; + /* --- * Build catalog decoding snapshot incrementally using information about * the currently running transactions. There are several ways to do that: @@ -1321,10 +1323,12 @@ SnapBuildFindSnapshot(SnapBuild *builder, XLogRecPtr lsn, xl_running_xacts *runn * state while waiting on c)'s sub-states. * * b) This (in a previous run) or another decoding slot serialized a - * snapshot to disk that we can use. Can't use this method for the - * initial snapshot when slot is being created and needs full snapshot - * for export or direct use, as that snapshot will only contain catalog - * modifying transactions. + * snapshot to disk that we can use. Can't use this method while finding + * the start point for decoding changes as the restart LSN would be an + * arbitrary LSN but we need to find the start point to extract changes + * where we won't see the data for partial transactions. Also, we cannot + * use this method when a slot needs a full snapshot for export or direct + * use, as that snapshot will only contain catalog modifying transactions. * * c) First incrementally build a snapshot for catalog tuples * (BUILDING_SNAPSHOT), that requires all, already in-progress, @@ -1389,8 +1393,13 @@ SnapBuildFindSnapshot(SnapBuild *builder, XLogRecPtr lsn, xl_running_xacts *runn return false; } - /* b) valid on disk state and not building full snapshot */ + + /* + * b) valid on disk state and while neither building full snapshot nor + * creating a slot. + */ else if (!builder->building_full_snapshot && + !ctx->in_create && SnapBuildRestore(builder, lsn)) { int nxacts = running->subxcnt + running->xcnt; diff --git a/src/include/replication/logical.h b/src/include/replication/logical.h index 718080d54a7..89f9893b472 100644 --- a/src/include/replication/logical.h +++ b/src/include/replication/logical.h @@ -90,6 +90,12 @@ typedef struct LogicalDecodingContext bool prepared_write; XLogRecPtr write_location; TransactionId write_xid; + + /* + * True if the logical decoding context being used for the creation + * of a logical replication slot. + */ + bool in_create; } LogicalDecodingContext; |