1
0
mirror of https://github.com/postgres/postgres.git synced 2025-10-31 10:30:33 +03:00
Files
postgres/src/backend/replication/logical/syncutils.c
Amit Kapila 3e8e05596a Add worker type argument to logical replication worker functions.
Extend logicalrep_worker_stop, logicalrep_worker_wakeup, and
logicalrep_worker_find to accept a worker type argument. This change
enables differentiation between logical replication worker types, such as
apply workers and table sync workers. While preserving existing behavior,
it lays the groundwork for upcoming patch to add sequence synchronization
workers.

Author: Vignesh C <vignesh21@gmail.com>
Reviewed-by: shveta malik <shveta.malik@gmail.com>
Reviewed-by: Peter Smith <smithpb2250@gmail.com>
Reviewed-by: Chao Li <li.evan.chao@gmail.com>
Reviewed-by: Hayato Kuroda <kuroda.hayato@fujitsu.com>
Reviewed-by: Amit Kapila <amit.kapila16@gmail.com>
Discussion: https://postgr.es/m/CAA4eK1LC+KJiAkSrpE_NwvNdidw9F2os7GERUeSxSKv71gXysQ@mail.gmail.com
2025-10-28 05:47:50 +00:00

190 lines
5.1 KiB
C

/*-------------------------------------------------------------------------
* syncutils.c
* PostgreSQL logical replication: common synchronization code
*
* Copyright (c) 2025, PostgreSQL Global Development Group
*
* IDENTIFICATION
* src/backend/replication/logical/syncutils.c
*
* NOTES
* This file contains code common for synchronization workers.
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "catalog/pg_subscription_rel.h"
#include "pgstat.h"
#include "replication/worker_internal.h"
#include "storage/ipc.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
/*
* Enum for phases of the subscription relations state.
*
* SYNC_RELATIONS_STATE_NEEDS_REBUILD indicates that the subscription relations
* state is no longer valid, and the subscription relations should be rebuilt.
*
* SYNC_RELATIONS_STATE_REBUILD_STARTED indicates that the subscription
* relations state is being rebuilt.
*
* SYNC_RELATIONS_STATE_VALID indicates that the subscription relation state is
* up-to-date and valid.
*/
typedef enum
{
SYNC_RELATIONS_STATE_NEEDS_REBUILD,
SYNC_RELATIONS_STATE_REBUILD_STARTED,
SYNC_RELATIONS_STATE_VALID,
} SyncingRelationsState;
static SyncingRelationsState relation_states_validity = SYNC_RELATIONS_STATE_NEEDS_REBUILD;
/*
* Exit routine for synchronization worker.
*/
pg_noreturn void
FinishSyncWorker(void)
{
/*
* Commit any outstanding transaction. This is the usual case, unless
* there was nothing to do for the table.
*/
if (IsTransactionState())
{
CommitTransactionCommand();
pgstat_report_stat(true);
}
/* And flush all writes. */
XLogFlush(GetXLogWriteRecPtr());
StartTransactionCommand();
ereport(LOG,
(errmsg("logical replication table synchronization worker for subscription \"%s\", table \"%s\" has finished",
MySubscription->name,
get_rel_name(MyLogicalRepWorker->relid))));
CommitTransactionCommand();
/* Find the leader apply worker and signal it. */
logicalrep_worker_wakeup(WORKERTYPE_APPLY, MyLogicalRepWorker->subid,
InvalidOid);
/* Stop gracefully */
proc_exit(0);
}
/*
* Callback from syscache invalidation.
*/
void
InvalidateSyncingRelStates(Datum arg, int cacheid, uint32 hashvalue)
{
relation_states_validity = SYNC_RELATIONS_STATE_NEEDS_REBUILD;
}
/*
* Process possible state change(s) of relations that are being synchronized.
*/
void
ProcessSyncingRelations(XLogRecPtr current_lsn)
{
switch (MyLogicalRepWorker->type)
{
case WORKERTYPE_PARALLEL_APPLY:
/*
* Skip for parallel apply workers because they only operate on
* tables that are in a READY state. See pa_can_start() and
* should_apply_changes_for_rel().
*/
break;
case WORKERTYPE_TABLESYNC:
ProcessSyncingTablesForSync(current_lsn);
break;
case WORKERTYPE_APPLY:
ProcessSyncingTablesForApply(current_lsn);
break;
case WORKERTYPE_UNKNOWN:
/* Should never happen. */
elog(ERROR, "Unknown worker type");
}
}
/*
* Common code to fetch the up-to-date sync state info into the static lists.
*
* Returns true if subscription has 1 or more tables, else false.
*
* Note: If this function started the transaction (indicated by the parameter)
* then it is the caller's responsibility to commit it.
*/
bool
FetchRelationStates(bool *started_tx)
{
static bool has_subtables = false;
*started_tx = false;
if (relation_states_validity != SYNC_RELATIONS_STATE_VALID)
{
MemoryContext oldctx;
List *rstates;
ListCell *lc;
SubscriptionRelState *rstate;
relation_states_validity = SYNC_RELATIONS_STATE_REBUILD_STARTED;
/* Clean the old lists. */
list_free_deep(table_states_not_ready);
table_states_not_ready = NIL;
if (!IsTransactionState())
{
StartTransactionCommand();
*started_tx = true;
}
/* Fetch tables that are in non-ready state. */
rstates = GetSubscriptionRelations(MySubscription->oid, true, false,
true);
/* Allocate the tracking info in a permanent memory context. */
oldctx = MemoryContextSwitchTo(CacheMemoryContext);
foreach(lc, rstates)
{
rstate = palloc(sizeof(SubscriptionRelState));
memcpy(rstate, lfirst(lc), sizeof(SubscriptionRelState));
table_states_not_ready = lappend(table_states_not_ready, rstate);
}
MemoryContextSwitchTo(oldctx);
/*
* Does the subscription have tables?
*
* If there were not-READY tables found then we know it does. But if
* table_states_not_ready was empty we still need to check again to
* see if there are 0 tables.
*/
has_subtables = (table_states_not_ready != NIL) ||
HasSubscriptionTables(MySubscription->oid);
/*
* If the subscription relation cache has been invalidated since we
* entered this routine, we still use and return the relations we just
* finished constructing, to avoid infinite loops, but we leave the
* table states marked as stale so that we'll rebuild it again on next
* access. Otherwise, we mark the table states as valid.
*/
if (relation_states_validity == SYNC_RELATIONS_STATE_REBUILD_STARTED)
relation_states_validity = SYNC_RELATIONS_STATE_VALID;
}
return has_subtables;
}