Fix assertion failure in snapshot building
authorDaniel Gustafsson <[email protected]>
Tue, 4 Jul 2023 15:36:13 +0000 (17:36 +0200)
committerDaniel Gustafsson <[email protected]>
Tue, 4 Jul 2023 15:36:13 +0000 (17:36 +0200)
Clear any potential stale next_phase_at value from the snapshot
builder which otherwise may trip an assertion check ensuring
that there is no next_phase_at value.

This can be reproduced by running 80 concurrent sessions like
the below where $c is a loop counter (assumes there has been
1..$c databases created) :

  echo "
    CREATE TABLE replication_example(id SERIAL PRIMARY KEY,
                                     somedata int,
                                     text varchar(120));
    SELECT 'init' FROM
      pg_create_logical_replication_slot('regression_slot_$c',
                                         'test_decoding');
    SELECT data FROM
      pg_logical_slot_get_changes('regression_slot_$c', NULL,
                                  NULL, 'include-xids', '0',
                                  'skip-empty-xacts', '1');
  " | psql -d regress_$c >>psql.log &

Back down to v16.

Bug: #17695
Author: Masahiko Sawada <[email protected]>
Reviewed-by: Alexander Lakhin <[email protected]>
Reported-by: bowenshi <[email protected]>
Discussion: https://postgr.es/m/17695-6be9277c9295985f@postgresql.org
Back-through: v16

src/backend/replication/logical/snapbuild.c

index e403feeccdad6d8608a44b3c6f0145d15b106f21..843ceba840bb8d4339a67b8c8f55592d32f92a3c 100644 (file)
@@ -1955,8 +1955,12 @@ SnapBuildRestore(SnapBuild *builder, XLogRecPtr lsn)
    if (TransactionIdPrecedes(ondisk.builder.xmin, builder->initial_xmin_horizon))
        goto snapshot_not_interesting;
 
-   /* consistent snapshots have no next phase */
+   /*
+    * Consistent snapshots have no next phase. Reset next_phase_at as it is
+    * possible that an old value may remain.
+    */
    Assert(ondisk.builder.next_phase_at == InvalidTransactionId);
+   builder->next_phase_at = InvalidTransactionId;
 
    /* ok, we think the snapshot is sensible, copy over everything important */
    builder->xmin = ondisk.builder.xmin;