mirror of
https://github.com/postgres/postgres.git
synced 2025-11-09 06:21:09 +03:00
Add sequence synchronization for logical replication.
This patch introduces sequence synchronization. Sequences that are synced
will have 2 states:
- INIT (needs [re]synchronizing)
- READY (is already synchronized)
A new sequencesync worker is launched as needed to synchronize sequences.
A single sequencesync worker is responsible for synchronizing all
sequences. It begins by retrieving the list of sequences that are flagged
for synchronization, i.e., those in the INIT state. These sequences are
then processed in batches, allowing multiple entries to be synchronized
within a single transaction. The worker fetches the current sequence
values and page LSNs from the remote publisher, updates the corresponding
sequences on the local subscriber, and finally marks each sequence as
READY upon successful synchronization.
Sequence synchronization occurs in 3 places:
1) CREATE SUBSCRIPTION
- The command syntax remains unchanged.
- The subscriber retrieves sequences associated with publications.
- Published sequences are added to pg_subscription_rel with INIT
state.
- Initiate the sequencesync worker to synchronize all sequences.
2) ALTER SUBSCRIPTION ... REFRESH PUBLICATION
- The command syntax remains unchanged.
- Dropped published sequences are removed from pg_subscription_rel.
- Newly published sequences are added to pg_subscription_rel with INIT
state.
- Initiate the sequencesync worker to synchronize only newly added
sequences.
3) ALTER SUBSCRIPTION ... REFRESH SEQUENCES
- A new command introduced for PG19 by f0b3573c3a.
- All sequences in pg_subscription_rel are reset to INIT state.
- Initiate the sequencesync worker to synchronize all sequences.
- Unlike "ALTER SUBSCRIPTION ... REFRESH PUBLICATION" command,
addition and removal of missing sequences will not be done in this
case.
Author: Vignesh C <vignesh21@gmail.com>
Reviewed-by: shveta malik <shveta.malik@gmail.com>
Reviewed-by: Hou Zhijie <houzj.fnst@fujitsu.com>
Reviewed-by: Masahiko Sawada <sawada.mshk@gmail.com>
Reviewed-by: Hayato Kuroda <kuroda.hayato@fujitsu.com>
Reviewed-by: Dilip Kumar <dilipbalaut@gmail.com>
Reviewed-by: Peter Smith <smithpb2250@gmail.com>
Reviewed-by: Nisha Moond <nisha.moond412@gmail.com>
Reviewed-by: Shlok Kyal <shlok.kyal.oss@gmail.com>
Reviewed-by: Amit Kapila <amit.kapila16@gmail.com>
Reviewed-by: Chao Li <li.evan.chao@gmail.com>
Discussion: https://postgr.es/m/CAA4eK1LC+KJiAkSrpE_NwvNdidw9F2os7GERUeSxSKv71gXysQ@mail.gmail.com
This commit is contained in:
@@ -374,14 +374,14 @@ ProcessSyncingTablesForApply(XLogRecPtr current_lsn)
|
||||
};
|
||||
static HTAB *last_start_times = NULL;
|
||||
ListCell *lc;
|
||||
bool started_tx = false;
|
||||
bool started_tx;
|
||||
bool should_exit = false;
|
||||
Relation rel = NULL;
|
||||
|
||||
Assert(!IsTransactionState());
|
||||
|
||||
/* We need up-to-date sync state info for subscription tables here. */
|
||||
FetchRelationStates(&started_tx);
|
||||
FetchRelationStates(NULL, NULL, &started_tx);
|
||||
|
||||
/*
|
||||
* Prepare a hash table for tracking last start times of workers, to avoid
|
||||
@@ -415,6 +415,14 @@ ProcessSyncingTablesForApply(XLogRecPtr current_lsn)
|
||||
{
|
||||
SubscriptionRelState *rstate = (SubscriptionRelState *) lfirst(lc);
|
||||
|
||||
if (!started_tx)
|
||||
{
|
||||
StartTransactionCommand();
|
||||
started_tx = true;
|
||||
}
|
||||
|
||||
Assert(get_rel_relkind(rstate->relid) != RELKIND_SEQUENCE);
|
||||
|
||||
if (rstate->state == SUBREL_STATE_SYNCDONE)
|
||||
{
|
||||
/*
|
||||
@@ -428,11 +436,6 @@ ProcessSyncingTablesForApply(XLogRecPtr current_lsn)
|
||||
|
||||
rstate->state = SUBREL_STATE_READY;
|
||||
rstate->lsn = current_lsn;
|
||||
if (!started_tx)
|
||||
{
|
||||
StartTransactionCommand();
|
||||
started_tx = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove the tablesync origin tracking if exists.
|
||||
@@ -552,43 +555,19 @@ ProcessSyncingTablesForApply(XLogRecPtr current_lsn)
|
||||
*/
|
||||
int nsyncworkers =
|
||||
logicalrep_sync_worker_count(MyLogicalRepWorker->subid);
|
||||
struct tablesync_start_time_mapping *hentry;
|
||||
bool found;
|
||||
|
||||
/* Now safe to release the LWLock */
|
||||
LWLockRelease(LogicalRepWorkerLock);
|
||||
|
||||
/*
|
||||
* If there are free sync worker slot(s), start a new sync
|
||||
* worker for the table.
|
||||
*/
|
||||
if (nsyncworkers < max_sync_workers_per_subscription)
|
||||
{
|
||||
TimestampTz now = GetCurrentTimestamp();
|
||||
struct tablesync_start_time_mapping *hentry;
|
||||
bool found;
|
||||
hentry = hash_search(last_start_times, &rstate->relid,
|
||||
HASH_ENTER, &found);
|
||||
if (!found)
|
||||
hentry->last_start_time = 0;
|
||||
|
||||
hentry = hash_search(last_start_times, &rstate->relid,
|
||||
HASH_ENTER, &found);
|
||||
|
||||
if (!found ||
|
||||
TimestampDifferenceExceeds(hentry->last_start_time, now,
|
||||
wal_retrieve_retry_interval))
|
||||
{
|
||||
/*
|
||||
* Set the last_start_time even if we fail to start
|
||||
* the worker, so that we won't retry until
|
||||
* wal_retrieve_retry_interval has elapsed.
|
||||
*/
|
||||
hentry->last_start_time = now;
|
||||
(void) logicalrep_worker_launch(WORKERTYPE_TABLESYNC,
|
||||
MyLogicalRepWorker->dbid,
|
||||
MySubscription->oid,
|
||||
MySubscription->name,
|
||||
MyLogicalRepWorker->userid,
|
||||
rstate->relid,
|
||||
DSM_HANDLE_INVALID,
|
||||
false);
|
||||
}
|
||||
}
|
||||
launch_sync_worker(WORKERTYPE_TABLESYNC, nsyncworkers,
|
||||
rstate->relid, &hentry->last_start_time);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1432,8 +1411,8 @@ LogicalRepSyncTableStart(XLogRecPtr *origin_startpos)
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure that the copy command runs as the table owner, unless the
|
||||
* user has opted out of that behaviour.
|
||||
* If the user did not opt to run as the owner of the subscription
|
||||
* ('run_as_owner'), then copy the table as the owner of the table.
|
||||
*/
|
||||
run_as_owner = MySubscription->runasowner;
|
||||
if (!run_as_owner)
|
||||
@@ -1596,7 +1575,7 @@ run_tablesync_worker()
|
||||
|
||||
/* Logical Replication Tablesync worker entry point */
|
||||
void
|
||||
TablesyncWorkerMain(Datum main_arg)
|
||||
TableSyncWorkerMain(Datum main_arg)
|
||||
{
|
||||
int worker_slot = DatumGetInt32(main_arg);
|
||||
|
||||
@@ -1618,11 +1597,11 @@ TablesyncWorkerMain(Datum main_arg)
|
||||
bool
|
||||
AllTablesyncsReady(void)
|
||||
{
|
||||
bool started_tx = false;
|
||||
bool has_subrels = false;
|
||||
bool started_tx;
|
||||
bool has_tables;
|
||||
|
||||
/* We need up-to-date sync state info for subscription tables here. */
|
||||
has_subrels = FetchRelationStates(&started_tx);
|
||||
FetchRelationStates(&has_tables, NULL, &started_tx);
|
||||
|
||||
if (started_tx)
|
||||
{
|
||||
@@ -1634,7 +1613,7 @@ AllTablesyncsReady(void)
|
||||
* Return false when there are no tables in subscription or not all tables
|
||||
* are in ready state; true otherwise.
|
||||
*/
|
||||
return has_subrels && (table_states_not_ready == NIL);
|
||||
return has_tables && (table_states_not_ready == NIL);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1649,10 +1628,10 @@ bool
|
||||
HasSubscriptionTablesCached(void)
|
||||
{
|
||||
bool started_tx;
|
||||
bool has_subrels;
|
||||
bool has_tables;
|
||||
|
||||
/* We need up-to-date subscription tables info here */
|
||||
has_subrels = FetchRelationStates(&started_tx);
|
||||
FetchRelationStates(&has_tables, NULL, &started_tx);
|
||||
|
||||
if (started_tx)
|
||||
{
|
||||
@@ -1660,7 +1639,7 @@ HasSubscriptionTablesCached(void)
|
||||
pgstat_report_stat(true);
|
||||
}
|
||||
|
||||
return has_subrels;
|
||||
return has_tables;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user