diff options
author | Amit Kapila <akapila@postgresql.org> | 2024-09-04 08:55:21 +0530 |
---|---|---|
committer | Amit Kapila <akapila@postgresql.org> | 2024-09-04 08:55:21 +0530 |
commit | 6c2b5edecc0d6c936e27775c9451d32bb3141c90 (patch) | |
tree | a3717ebb364195cceaac32754aec901072531f98 /src/test | |
parent | 9626068f13338f79ba183b4cf3c975e22c98c575 (diff) | |
download | postgresql-6c2b5edecc0d6c936e27775c9451d32bb3141c90.tar.gz postgresql-6c2b5edecc0d6c936e27775c9451d32bb3141c90.zip |
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
Diffstat (limited to 'src/test')
-rw-r--r-- | src/test/regress/expected/rules.out | 8 | ||||
-rw-r--r-- | src/test/subscription/t/026_stats.pl | 61 |
2 files changed, 51 insertions, 18 deletions
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out index 862433ee52b..a1626f3fae9 100644 --- a/src/test/regress/expected/rules.out +++ b/src/test/regress/expected/rules.out @@ -2139,9 +2139,15 @@ pg_stat_subscription_stats| SELECT ss.subid, s.subname, ss.apply_error_count, ss.sync_error_count, + ss.confl_insert_exists, + ss.confl_update_origin_differs, + ss.confl_update_exists, + ss.confl_update_missing, + ss.confl_delete_origin_differs, + ss.confl_delete_missing, ss.stats_reset FROM pg_subscription s, - LATERAL pg_stat_get_subscription_stats(s.oid) ss(subid, apply_error_count, sync_error_count, stats_reset); + LATERAL pg_stat_get_subscription_stats(s.oid) ss(subid, apply_error_count, sync_error_count, confl_insert_exists, confl_update_origin_differs, confl_update_exists, confl_update_missing, confl_delete_origin_differs, confl_delete_missing, stats_reset); pg_stat_sys_indexes| SELECT relid, indexrelid, schemaname, diff --git a/src/test/subscription/t/026_stats.pl b/src/test/subscription/t/026_stats.pl index fb3e5629b3c..6b6a5b0b1b6 100644 --- a/src/test/subscription/t/026_stats.pl +++ b/src/test/subscription/t/026_stats.pl @@ -30,6 +30,7 @@ sub create_sub_pub_w_errors qq[ BEGIN; CREATE TABLE $table_name(a int); + ALTER TABLE $table_name REPLICA IDENTITY FULL; INSERT INTO $table_name VALUES (1); COMMIT; ]); @@ -91,20 +92,36 @@ sub create_sub_pub_w_errors # subscriber due to violation of the unique constraint on test table. $node_publisher->safe_psql($db, qq(INSERT INTO $table_name VALUES (1))); - # Wait for the apply error to be reported. + # Wait for the subscriber to report both an apply error and an + # insert_exists conflict. $node_subscriber->poll_query_until( $db, qq[ - SELECT apply_error_count > 0 + SELECT apply_error_count > 0 AND confl_insert_exists > 0 FROM pg_stat_subscription_stats WHERE subname = '$sub_name' ]) or die - qq(Timed out while waiting for apply error for subscription '$sub_name'); + qq(Timed out while waiting for apply error and insert_exists conflict for subscription '$sub_name'); # Truncate test table so that apply worker can continue. $node_subscriber->safe_psql($db, qq(TRUNCATE $table_name)); + # Delete data from the test table on the publisher. This delete operation + # should be skipped on the subscriber since the table is already empty. + $node_publisher->safe_psql($db, qq(DELETE FROM $table_name;)); + + # Wait for the subscriber to report a delete_missing conflict. + $node_subscriber->poll_query_until( + $db, + qq[ + SELECT confl_delete_missing > 0 + FROM pg_stat_subscription_stats + WHERE subname = '$sub_name' + ]) + or die + qq(Timed out while waiting for delete_missing conflict for subscription '$sub_name'); + return ($pub_name, $sub_name); } @@ -123,17 +140,19 @@ my ($pub1_name, $sub1_name) = create_sub_pub_w_errors($node_publisher, $node_subscriber, $db, $table1_name); -# Apply and Sync errors are > 0 and reset timestamp is NULL +# Apply errors, sync errors, and conflicts are > 0 and stats_reset timestamp is NULL is( $node_subscriber->safe_psql( $db, qq(SELECT apply_error_count > 0, sync_error_count > 0, + confl_insert_exists > 0, + confl_delete_missing > 0, stats_reset IS NULL FROM pg_stat_subscription_stats WHERE subname = '$sub1_name') ), - qq(t|t|t), - qq(Check that apply errors and sync errors are both > 0 and stats_reset is NULL for subscription '$sub1_name'.) + qq(t|t|t|t|t), + qq(Check that apply errors, sync errors, and conflicts are > 0 and stats_reset is NULL for subscription '$sub1_name'.) ); # Reset a single subscription @@ -141,17 +160,19 @@ $node_subscriber->safe_psql($db, qq(SELECT pg_stat_reset_subscription_stats((SELECT subid FROM pg_stat_subscription_stats WHERE subname = '$sub1_name'))) ); -# Apply and Sync errors are 0 and stats reset is not NULL +# Apply errors, sync errors, and conflicts are 0 and stats_reset timestamp is not NULL is( $node_subscriber->safe_psql( $db, qq(SELECT apply_error_count = 0, sync_error_count = 0, + confl_insert_exists = 0, + confl_delete_missing = 0, stats_reset IS NOT NULL FROM pg_stat_subscription_stats WHERE subname = '$sub1_name') ), - qq(t|t|t), - qq(Confirm that apply errors and sync errors are both 0 and stats_reset is not NULL after reset for subscription '$sub1_name'.) + qq(t|t|t|t|t), + qq(Confirm that apply errors, sync errors, and conflicts are 0 and stats_reset is not NULL after reset for subscription '$sub1_name'.) ); # Get reset timestamp @@ -181,46 +202,52 @@ my ($pub2_name, $sub2_name) = create_sub_pub_w_errors($node_publisher, $node_subscriber, $db, $table2_name); -# Apply and Sync errors are > 0 and reset timestamp is NULL +# Apply errors, sync errors, and conflicts are > 0 and stats_reset timestamp is NULL is( $node_subscriber->safe_psql( $db, qq(SELECT apply_error_count > 0, sync_error_count > 0, + confl_insert_exists > 0, + confl_delete_missing > 0, stats_reset IS NULL FROM pg_stat_subscription_stats WHERE subname = '$sub2_name') ), - qq(t|t|t), - qq(Confirm that apply errors and sync errors are both > 0 and stats_reset is NULL for sub '$sub2_name'.) + qq(t|t|t|t|t), + qq(Confirm that apply errors, sync errors, and conflicts are > 0 and stats_reset is NULL for sub '$sub2_name'.) ); # Reset all subscriptions $node_subscriber->safe_psql($db, qq(SELECT pg_stat_reset_subscription_stats(NULL))); -# Apply and Sync errors are 0 and stats reset is not NULL +# Apply errors, sync errors, and conflicts are 0 and stats_reset timestamp is not NULL is( $node_subscriber->safe_psql( $db, qq(SELECT apply_error_count = 0, sync_error_count = 0, + confl_insert_exists = 0, + confl_delete_missing = 0, stats_reset IS NOT NULL FROM pg_stat_subscription_stats WHERE subname = '$sub1_name') ), - qq(t|t|t), - qq(Confirm that apply errors and sync errors are both 0 and stats_reset is not NULL for sub '$sub1_name' after reset.) + qq(t|t|t|t|t), + qq(Confirm that apply errors, sync errors, and conflicts are 0 and stats_reset is not NULL for sub '$sub1_name' after reset.) ); is( $node_subscriber->safe_psql( $db, qq(SELECT apply_error_count = 0, sync_error_count = 0, + confl_insert_exists = 0, + confl_delete_missing = 0, stats_reset IS NOT NULL FROM pg_stat_subscription_stats WHERE subname = '$sub2_name') ), - qq(t|t|t), - qq(Confirm that apply errors and sync errors are both 0 and stats_reset is not NULL for sub '$sub2_name' after reset.) + qq(t|t|t|t|t), + qq(Confirm that apply errors, sync errors, and conflicts are 0 and stats_reset is not NULL for sub '$sub2_name' after reset.) ); $reset_time1 = $node_subscriber->safe_psql($db, |