diff --git a/src/backend/commands/subscriptioncmds.c b/src/backend/commands/subscriptioncmds.c index 4292e7fb8f4..3de358f9374 100644 --- a/src/backend/commands/subscriptioncmds.c +++ b/src/backend/commands/subscriptioncmds.c @@ -1363,6 +1363,33 @@ AlterSubscription_refresh_seq(Subscription *sub) WalReceiverConn *wrconn; bool must_use_password; + /* + * Disallow a concurrent REFRESH SEQUENCES while a sequence sync worker + * for this subscription is still running. This avoids a race where the + * publisher's sequence advances after the current worker has fetched its + * value but before it marks the sequence READY. A user may then issue + * another REFRESH SEQUENCES to synchronize the updated value. Since the + * affected sequences are already in the INIT state, the running worker + * has no indication that a new synchronization has been requested. It + * would then apply the stale value it already fetched and mark the + * sequence READY, causing the new synchronization request to be lost and + * preventing the updated publisher values from being synchronized. + */ + LWLockAcquire(LogicalRepWorkerLock, LW_SHARED); + if (logicalrep_worker_find(WORKERTYPE_SEQUENCESYNC, sub->oid, InvalidOid, + true)) + { + LWLockRelease(LogicalRepWorkerLock); + ereport(ERROR, + errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), + /* translator: %s is an SQL ALTER command */ + errmsg("cannot execute %s while a sequence synchronization worker is running", + "ALTER SUBSCRIPTION ... REFRESH SEQUENCES"), + errhint("Try again after the current synchronization completes.")); + } + + LWLockRelease(LogicalRepWorkerLock); + /* Load the library providing us libpq calls. */ load_file("libpqwalreceiver", false); diff --git a/src/test/subscription/t/036_sequences.pl b/src/test/subscription/t/036_sequences.pl index 2a0819aaf01..8b02b24a7e9 100644 --- a/src/test/subscription/t/036_sequences.pl +++ b/src/test/subscription/t/036_sequences.pl @@ -232,6 +232,10 @@ $node_publisher->safe_psql( CREATE SEQUENCE regress_s4 START 10 INCREMENT 2; )); +# Wait for the missing sequence added to be synced +$node_subscriber->poll_query_until('postgres', $synced_query) + or die "Timed out while waiting for subscriber to synchronize data"; + ########## # Ensure that insufficient privileges on the publisher for a sequence # are reported correctly as a permission issue, not as a missing sequence.