mirror of
https://github.com/postgres/postgres.git
synced 2025-11-22 12:22:45 +03:00
Collect statistics about conflicts in logical replication.
This commit adds columns in view pg_stat_subscription_stats to show the
number of times a particular conflict type has occurred during the
application of logical replication changes. The following columns are
added:
confl_insert_exists:
Number of times a row insertion violated a NOT DEFERRABLE unique
constraint.
confl_update_origin_differs:
Number of times an update was performed on a row that was
previously modified by another origin.
confl_update_exists:
Number of times that the updated value of a row violates a
NOT DEFERRABLE unique constraint.
confl_update_missing:
Number of times that the tuple to be updated is missing.
confl_delete_origin_differs:
Number of times a delete was performed on a row that was
previously modified by another origin.
confl_delete_missing:
Number of times that the tuple to be deleted is missing.
The update_origin_differs and delete_origin_differs conflicts can be
detected only when track_commit_timestamp is enabled.
Author: Hou Zhijie
Reviewed-by: Shveta Malik, Peter Smith, Anit Kapila
Discussion: https://postgr.es/m/OS0PR01MB57160A07BD575773045FC214948F2@OS0PR01MB5716.jpnprd01.prod.outlook.com
This commit is contained in:
@@ -39,6 +39,21 @@ pgstat_report_subscription_error(Oid subid, bool is_apply_error)
|
||||
pending->sync_error_count++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Report a subscription conflict.
|
||||
*/
|
||||
void
|
||||
pgstat_report_subscription_conflict(Oid subid, ConflictType type)
|
||||
{
|
||||
PgStat_EntryRef *entry_ref;
|
||||
PgStat_BackendSubEntry *pending;
|
||||
|
||||
entry_ref = pgstat_prep_pending_entry(PGSTAT_KIND_SUBSCRIPTION,
|
||||
InvalidOid, subid, NULL);
|
||||
pending = entry_ref->pending;
|
||||
pending->conflict_count[type]++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Report creating the subscription.
|
||||
*/
|
||||
@@ -101,6 +116,8 @@ pgstat_subscription_flush_cb(PgStat_EntryRef *entry_ref, bool nowait)
|
||||
#define SUB_ACC(fld) shsubent->stats.fld += localent->fld
|
||||
SUB_ACC(apply_error_count);
|
||||
SUB_ACC(sync_error_count);
|
||||
for (int i = 0; i < CONFLICT_NUM_TYPES; i++)
|
||||
SUB_ACC(conflict_count[i]);
|
||||
#undef SUB_ACC
|
||||
|
||||
pgstat_unlock_entry(entry_ref);
|
||||
|
||||
@@ -1966,13 +1966,14 @@ pg_stat_get_replication_slot(PG_FUNCTION_ARGS)
|
||||
Datum
|
||||
pg_stat_get_subscription_stats(PG_FUNCTION_ARGS)
|
||||
{
|
||||
#define PG_STAT_GET_SUBSCRIPTION_STATS_COLS 4
|
||||
#define PG_STAT_GET_SUBSCRIPTION_STATS_COLS 10
|
||||
Oid subid = PG_GETARG_OID(0);
|
||||
TupleDesc tupdesc;
|
||||
Datum values[PG_STAT_GET_SUBSCRIPTION_STATS_COLS] = {0};
|
||||
bool nulls[PG_STAT_GET_SUBSCRIPTION_STATS_COLS] = {0};
|
||||
PgStat_StatSubEntry *subentry;
|
||||
PgStat_StatSubEntry allzero;
|
||||
int i = 0;
|
||||
|
||||
/* Get subscription stats */
|
||||
subentry = pgstat_fetch_stat_subscription(subid);
|
||||
@@ -1985,7 +1986,19 @@ pg_stat_get_subscription_stats(PG_FUNCTION_ARGS)
|
||||
INT8OID, -1, 0);
|
||||
TupleDescInitEntry(tupdesc, (AttrNumber) 3, "sync_error_count",
|
||||
INT8OID, -1, 0);
|
||||
TupleDescInitEntry(tupdesc, (AttrNumber) 4, "stats_reset",
|
||||
TupleDescInitEntry(tupdesc, (AttrNumber) 4, "confl_insert_exists",
|
||||
INT8OID, -1, 0);
|
||||
TupleDescInitEntry(tupdesc, (AttrNumber) 5, "confl_update_origin_differs",
|
||||
INT8OID, -1, 0);
|
||||
TupleDescInitEntry(tupdesc, (AttrNumber) 6, "confl_update_exists",
|
||||
INT8OID, -1, 0);
|
||||
TupleDescInitEntry(tupdesc, (AttrNumber) 7, "confl_update_missing",
|
||||
INT8OID, -1, 0);
|
||||
TupleDescInitEntry(tupdesc, (AttrNumber) 8, "confl_delete_origin_differs",
|
||||
INT8OID, -1, 0);
|
||||
TupleDescInitEntry(tupdesc, (AttrNumber) 9, "confl_delete_missing",
|
||||
INT8OID, -1, 0);
|
||||
TupleDescInitEntry(tupdesc, (AttrNumber) 10, "stats_reset",
|
||||
TIMESTAMPTZOID, -1, 0);
|
||||
BlessTupleDesc(tupdesc);
|
||||
|
||||
@@ -1997,19 +2010,25 @@ pg_stat_get_subscription_stats(PG_FUNCTION_ARGS)
|
||||
}
|
||||
|
||||
/* subid */
|
||||
values[0] = ObjectIdGetDatum(subid);
|
||||
values[i++] = ObjectIdGetDatum(subid);
|
||||
|
||||
/* apply_error_count */
|
||||
values[1] = Int64GetDatum(subentry->apply_error_count);
|
||||
values[i++] = Int64GetDatum(subentry->apply_error_count);
|
||||
|
||||
/* sync_error_count */
|
||||
values[2] = Int64GetDatum(subentry->sync_error_count);
|
||||
values[i++] = Int64GetDatum(subentry->sync_error_count);
|
||||
|
||||
/* conflict count */
|
||||
for (int nconflict = 0; nconflict < CONFLICT_NUM_TYPES; nconflict++)
|
||||
values[i++] = Int64GetDatum(subentry->conflict_count[nconflict]);
|
||||
|
||||
/* stats_reset */
|
||||
if (subentry->stat_reset_timestamp == 0)
|
||||
nulls[3] = true;
|
||||
nulls[i] = true;
|
||||
else
|
||||
values[3] = TimestampTzGetDatum(subentry->stat_reset_timestamp);
|
||||
values[i] = TimestampTzGetDatum(subentry->stat_reset_timestamp);
|
||||
|
||||
Assert(i + 1 == PG_STAT_GET_SUBSCRIPTION_STATS_COLS);
|
||||
|
||||
/* Returns the record as Datum */
|
||||
PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
|
||||
|
||||
Reference in New Issue
Block a user