Hi Vignesh, Here are my v20240807-0003 review comments. ====== 1. GENERAL DOCS.
IMO the replication of SEQUENCES is a big enough topic that it deserves to have its own section in the docs chapter 31 [1]. Some of the create/alter subscription docs content would stay where it is in, but a new chapter would just tie everything together better. It could also serve as a better place to describe the other sequence replication content like: (a) getting a WARNING for mismatched sequences and how to handle it. (b) how can the user know when a subscription refresh is required to (re-)synchronise sequences (c) pub/sub examples ====== doc/src/sgml/logical-replication.sgml 2. Restrictions Sequence data is not replicated. The data in serial or identity columns backed by sequences will of course be replicated as part of the table, but the sequence itself would still show the start value on the subscriber. If the subscriber is used as a read-only database, then this should typically not be a problem. If, however, some kind of switchover or failover to the subscriber database is intended, then the sequences would need to be updated to the latest values, either by executing ALTER SUBSCRIPTION ... REFRESH PUBLICATION SEQUENCES or by copying the current data from the publisher (perhaps using pg_dump) or by determining a sufficiently high value from the tables themselves. ~ 2a. The paragraph starts by saying "Sequence data is not replicated.". It seems wrong now. Doesn't that need rewording or removing? ~ 2b. Should the info "If, however, some kind of switchover or failover..." be mentioned in the "Logical Replication Failover" section [2], instead of here? ====== doc/src/sgml/ref/alter_subscription.sgml 3. Sequence values may occasionally become out of sync due to updates in the publisher. To verify this, compare the pg_subscription_rel.srsublsn on the subscriber with the page_lsn obtained from the pg_sequence_state for the sequence on the publisher. If the sequence is still using prefetched values, the page_lsn will not be updated. In such cases, you will need to directly compare the sequences and execute REFRESH PUBLICATION SEQUENCES if required. ~ 3a. This whole paragraph may be better put in the new chapter that was suggested earlier in review comment #1. ~ 3b. Is it only "Occasionally"? I expected subscriber-side sequences could become stale quite often. ~ 3c. Is this advice very useful? It's saying if the LSN is different then the sequence is out of date, but if the LSN is not different then you cannot tell. Why not ignore LSN altogether and just advise the user to directly compare the sequences in the first place? ====== Also, there are more minor suggestions in the attached nitpicks diff. ====== [1] https://www.postgresql.org/docs/current/logical-replication.html [2] file:///usr/local/pg_oss/share/doc/postgresql/html/logical-replication-failover.html Kind Regards, Peter Smith. Fujitsu Australia
diff --git a/src/backend/commands/subscriptioncmds.c b/src/backend/commands/subscriptioncmds.c index 6b320b1..bb6aa8e 100644 --- a/src/backend/commands/subscriptioncmds.c +++ b/src/backend/commands/subscriptioncmds.c @@ -726,7 +726,7 @@ CreateSubscription(ParseState *pstate, CreateSubscriptionStmt *stmt, recordDependencyOnOwner(SubscriptionRelationId, subid, owner); /* - * XXX todo: If the subscription is for a sequence-only publication, + * XXX: If the subscription is for a sequence-only publication, * creating this origin is unnecessary at this point. It can be created * later during the ALTER SUBSCRIPTION ... REFRESH command, if the * publication is updated to include tables or tables in schemas. @@ -756,7 +756,7 @@ CreateSubscription(ParseState *pstate, CreateSubscriptionStmt *stmt, PG_TRY(); { - bool hastables = false; + bool has_tables; List *relations; char table_state; @@ -771,16 +771,14 @@ CreateSubscription(ParseState *pstate, CreateSubscriptionStmt *stmt, table_state = opts.copy_data ? SUBREL_STATE_INIT : SUBREL_STATE_READY; /* - * Get the table list from publisher and build local table status - * info. + * Build local relation status info. Relations are for both tables and + * sequences from the publisher. */ relations = fetch_table_list(wrconn, publications); - if (relations != NIL) - hastables = true; - - /* Include the sequence list from publisher. */ + has_tables = relations != NIL; relations = list_concat(relations, fetch_sequence_list(wrconn, publications)); + foreach_ptr(RangeVar, rv, relations) { Oid relid; @@ -800,7 +798,7 @@ CreateSubscription(ParseState *pstate, CreateSubscriptionStmt *stmt, * won't use the initial snapshot for anything, so no need to * export it. * - * XXX todo: If the subscription is for a sequence-only publication, + * XXX: If the subscription is for a sequence-only publication, * creating this slot is not necessary at the moment. It can be * created during the ALTER SUBSCRIPTION ... REFRESH command if the * publication is updated to include tables or tables in schema. @@ -827,7 +825,7 @@ CreateSubscription(ParseState *pstate, CreateSubscriptionStmt *stmt, * PENDING, to allow ALTER SUBSCRIPTION ... REFRESH * PUBLICATION to work. */ - if (opts.twophase && !opts.copy_data && hastables) + if (opts.twophase && !opts.copy_data && has_tables) twophase_enabled = true; walrcv_create_slot(wrconn, opts.slot_name, false, twophase_enabled, @@ -2475,7 +2473,7 @@ fetch_sequence_list(WalReceiverConn *wrconn, List *publications) " LATERAL pg_get_publication_sequences(p.pubname::text) gps(relid), pg_class c\n" " JOIN pg_namespace n ON n.oid = c.relnamespace\n" " JOIN pg_sequence s ON c.oid = s.seqrelid\n" - "WHERE c.oid = gps.relid AND p.pubname IN (\n"); + "WHERE c.oid = gps.relid AND p.pubname IN ("); get_publications_str(publications, &cmd, true); appendStringInfoChar(&cmd, ')'); diff --git a/src/backend/replication/logical/sequencesync.c b/src/backend/replication/logical/sequencesync.c index 2935c53..a79c8a3 100644 --- a/src/backend/replication/logical/sequencesync.c +++ b/src/backend/replication/logical/sequencesync.c @@ -18,8 +18,8 @@ * ALTER SUBSCRIPTION ... REFRESH PUBLICATION * ALTER SUBSCRIPTION ... REFRESH PUBLICATION SEQUENCES * - * Apply worker will periodically check if there are any sequences in INIT - * state and start a sequencesync worker. + * The apply worker will periodically check if there are any sequences in INIT + * state and will start a sequencesync worker if needed. * * The sequencesync worker retrieves the sequences to be synchronized from the * pg_subscription_rel catalog table. It synchronizes multiple sequences per @@ -35,16 +35,18 @@ * (100) sequences are synchronized per transaction. The locks on the sequence * relation will be periodically released at each transaction commit. * - * An alternative design was considered where the launcher process would + * XXX: An alternative design was considered where the launcher process would * periodically check for sequences that need syncing and then start the - * sequence sync worker. However, the approach of having the apply worker - * manage the sequence sync worker was chosen for the following reasons: a) It - * avoids overloading the launcher, which handles various other subscription - * requests. b) It offers a more straightforward path for extending support for - * incremental sequence synchronization. c) It utilizes the existing tablesync - * worker code to start the sequencesync process, thus preventing code - * duplication in the launcher. d) It simplifies code maintenance by - * consolidating changes to a single location rather than multiple components. + * sequencesync worker. However, the approach of having the apply worker + * manage the sequencesync worker was chosen for the following reasons: + * a) It avoids overloading the launcher, which handles various other + * subscription requests. + * b) It offers a more straightforward path for extending support for + * incremental sequence synchronization. + * c) It utilizes the existing tablesync worker code to start the sequencesync + * process, thus preventing code duplication in the launcher. + * d) It simplifies code maintenance by consolidating changes to a single + * location rather than multiple components. *------------------------------------------------------------------------- */ diff --git a/src/backend/replication/logical/tablesync.c b/src/backend/replication/logical/tablesync.c index 5800f21..011c579 100644 --- a/src/backend/replication/logical/tablesync.c +++ b/src/backend/replication/logical/tablesync.c @@ -1700,7 +1700,7 @@ copy_table_done: static bool FetchTableStates(void) { - static bool has_subrels = false; + static bool has_subtables = false; bool started_tx = false; if (relation_states_validity != SYNC_TABLE_STATE_VALID) @@ -1752,7 +1752,7 @@ FetchTableStates(void) * if table_states_not_ready was empty we still need to check again to * see if there are 0 tables. */ - has_subrels = (table_states_not_ready != NIL) || + has_subtables = (table_states_not_ready != NIL) || HasSubscriptionTables(MySubscription->oid); /* @@ -1772,7 +1772,7 @@ FetchTableStates(void) pgstat_report_stat(true); } - return has_subrels; + return has_subtables; } /*