mirror of
https://github.com/postgres/postgres.git
synced 2025-06-14 18:42:34 +03:00
pgstat: add/extend tests for resetting various kinds of stats.
- subscriber stats reset path was untested - slot stat sreset path for all slots was untested - pg_stat_database.sessions etc was untested - pg_stat_reset_shared() was untested, for any kind of shared stats - pg_stat_reset() was untested Author: Melanie Plageman <melanieplageman@gmail.com> Author: Andres Freund <andres@anarazel.de> Discussion: https://postgr.es/m/20220303021600.hs34ghqcw6zcokdh@alap3.anarazel.de
This commit is contained in:
@ -1,6 +1,9 @@
|
|||||||
-- predictability
|
-- predictability
|
||||||
SET synchronous_commit = on;
|
SET synchronous_commit = on;
|
||||||
SELECT 'init' FROM pg_create_logical_replication_slot('regression_slot_stats', 'test_decoding');
|
SELECT 'init' FROM
|
||||||
|
pg_create_logical_replication_slot('regression_slot_stats1', 'test_decoding') s1,
|
||||||
|
pg_create_logical_replication_slot('regression_slot_stats2', 'test_decoding') s2,
|
||||||
|
pg_create_logical_replication_slot('regression_slot_stats3', 'test_decoding') s3;
|
||||||
?column?
|
?column?
|
||||||
----------
|
----------
|
||||||
init
|
init
|
||||||
@ -10,7 +13,19 @@ CREATE TABLE stats_test(data text);
|
|||||||
-- non-spilled xact
|
-- non-spilled xact
|
||||||
SET logical_decoding_work_mem to '64MB';
|
SET logical_decoding_work_mem to '64MB';
|
||||||
INSERT INTO stats_test values(1);
|
INSERT INTO stats_test values(1);
|
||||||
SELECT count(*) FROM pg_logical_slot_get_changes('regression_slot_stats', NULL, NULL, 'skip-empty-xacts', '1');
|
SELECT count(*) FROM pg_logical_slot_get_changes('regression_slot_stats1', NULL, NULL, 'skip-empty-xacts', '1');
|
||||||
|
count
|
||||||
|
-------
|
||||||
|
3
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT count(*) FROM pg_logical_slot_get_changes('regression_slot_stats2', NULL, NULL, 'skip-empty-xacts', '1');
|
||||||
|
count
|
||||||
|
-------
|
||||||
|
3
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT count(*) FROM pg_logical_slot_get_changes('regression_slot_stats3', NULL, NULL, 'skip-empty-xacts', '1');
|
||||||
count
|
count
|
||||||
-------
|
-------
|
||||||
3
|
3
|
||||||
@ -22,31 +37,65 @@ SELECT pg_stat_force_next_flush();
|
|||||||
|
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
SELECT slot_name, spill_txns = 0 AS spill_txns, spill_count = 0 AS spill_count, total_txns > 0 AS total_txns, total_bytes > 0 AS total_bytes FROM pg_stat_replication_slots;
|
SELECT slot_name, spill_txns = 0 AS spill_txns, spill_count = 0 AS spill_count, total_txns > 0 AS total_txns, total_bytes > 0 AS total_bytes FROM pg_stat_replication_slots ORDER BY slot_name;
|
||||||
slot_name | spill_txns | spill_count | total_txns | total_bytes
|
slot_name | spill_txns | spill_count | total_txns | total_bytes
|
||||||
-----------------------+------------+-------------+------------+-------------
|
------------------------+------------+-------------+------------+-------------
|
||||||
regression_slot_stats | t | t | t | t
|
regression_slot_stats1 | t | t | t | t
|
||||||
(1 row)
|
regression_slot_stats2 | t | t | t | t
|
||||||
|
regression_slot_stats3 | t | t | t | t
|
||||||
|
(3 rows)
|
||||||
|
|
||||||
RESET logical_decoding_work_mem;
|
RESET logical_decoding_work_mem;
|
||||||
-- reset the slot stats
|
-- reset stats for one slot, others should be unaffected
|
||||||
SELECT pg_stat_reset_replication_slot('regression_slot_stats');
|
SELECT pg_stat_reset_replication_slot('regression_slot_stats1');
|
||||||
pg_stat_reset_replication_slot
|
pg_stat_reset_replication_slot
|
||||||
--------------------------------
|
--------------------------------
|
||||||
|
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
SELECT slot_name, spill_txns, spill_count, total_txns, total_bytes FROM pg_stat_replication_slots;
|
SELECT slot_name, spill_txns = 0 AS spill_txns, spill_count = 0 AS spill_count, total_txns > 0 AS total_txns, total_bytes > 0 AS total_bytes FROM pg_stat_replication_slots ORDER BY slot_name;
|
||||||
slot_name | spill_txns | spill_count | total_txns | total_bytes
|
slot_name | spill_txns | spill_count | total_txns | total_bytes
|
||||||
-----------------------+------------+-------------+------------+-------------
|
------------------------+------------+-------------+------------+-------------
|
||||||
regression_slot_stats | 0 | 0 | 0 | 0
|
regression_slot_stats1 | t | t | f | f
|
||||||
|
regression_slot_stats2 | t | t | t | t
|
||||||
|
regression_slot_stats3 | t | t | t | t
|
||||||
|
(3 rows)
|
||||||
|
|
||||||
|
-- reset stats for all slots
|
||||||
|
SELECT pg_stat_reset_replication_slot(NULL);
|
||||||
|
pg_stat_reset_replication_slot
|
||||||
|
--------------------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT slot_name, spill_txns = 0 AS spill_txns, spill_count = 0 AS spill_count, total_txns > 0 AS total_txns, total_bytes > 0 AS total_bytes FROM pg_stat_replication_slots ORDER BY slot_name;
|
||||||
|
slot_name | spill_txns | spill_count | total_txns | total_bytes
|
||||||
|
------------------------+------------+-------------+------------+-------------
|
||||||
|
regression_slot_stats1 | t | t | f | f
|
||||||
|
regression_slot_stats2 | t | t | f | f
|
||||||
|
regression_slot_stats3 | t | t | f | f
|
||||||
|
(3 rows)
|
||||||
|
|
||||||
|
-- verify accessing/resetting stats for non-existent slot does something reasonable
|
||||||
|
SELECT * FROM pg_stat_get_replication_slot('do-not-exist');
|
||||||
|
slot_name | spill_txns | spill_count | spill_bytes | stream_txns | stream_count | stream_bytes | total_txns | total_bytes | stats_reset
|
||||||
|
--------------+------------+-------------+-------------+-------------+--------------+--------------+------------+-------------+-------------
|
||||||
|
do-not-exist | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT pg_stat_reset_replication_slot('do-not-exist');
|
||||||
|
ERROR: replication slot "do-not-exist" does not exist
|
||||||
|
SELECT * FROM pg_stat_get_replication_slot('do-not-exist');
|
||||||
|
slot_name | spill_txns | spill_count | spill_bytes | stream_txns | stream_count | stream_bytes | total_txns | total_bytes | stats_reset
|
||||||
|
--------------+------------+-------------+-------------+-------------+--------------+--------------+------------+-------------+-------------
|
||||||
|
do-not-exist | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
-- spilling the xact
|
-- spilling the xact
|
||||||
BEGIN;
|
BEGIN;
|
||||||
INSERT INTO stats_test SELECT 'serialize-topbig--1:'||g.i FROM generate_series(1, 5000) g(i);
|
INSERT INTO stats_test SELECT 'serialize-topbig--1:'||g.i FROM generate_series(1, 5000) g(i);
|
||||||
COMMIT;
|
COMMIT;
|
||||||
SELECT count(*) FROM pg_logical_slot_peek_changes('regression_slot_stats', NULL, NULL, 'skip-empty-xacts', '1');
|
SELECT count(*) FROM pg_logical_slot_peek_changes('regression_slot_stats1', NULL, NULL, 'skip-empty-xacts', '1');
|
||||||
count
|
count
|
||||||
-------
|
-------
|
||||||
5002
|
5002
|
||||||
@ -63,30 +112,38 @@ SELECT pg_stat_force_next_flush();
|
|||||||
|
|
||||||
SELECT slot_name, spill_txns > 0 AS spill_txns, spill_count > 0 AS spill_count FROM pg_stat_replication_slots;
|
SELECT slot_name, spill_txns > 0 AS spill_txns, spill_count > 0 AS spill_count FROM pg_stat_replication_slots;
|
||||||
slot_name | spill_txns | spill_count
|
slot_name | spill_txns | spill_count
|
||||||
-----------------------+------------+-------------
|
------------------------+------------+-------------
|
||||||
regression_slot_stats | t | t
|
regression_slot_stats1 | t | t
|
||||||
(1 row)
|
regression_slot_stats2 | f | f
|
||||||
|
regression_slot_stats3 | f | f
|
||||||
|
(3 rows)
|
||||||
|
|
||||||
-- Ensure stats can be repeatedly accessed using the same stats snapshot. See
|
-- Ensure stats can be repeatedly accessed using the same stats snapshot. See
|
||||||
-- https://postgr.es/m/20210317230447.c7uc4g3vbs4wi32i%40alap3.anarazel.de
|
-- https://postgr.es/m/20210317230447.c7uc4g3vbs4wi32i%40alap3.anarazel.de
|
||||||
BEGIN;
|
BEGIN;
|
||||||
SELECT slot_name FROM pg_stat_replication_slots;
|
SELECT slot_name FROM pg_stat_replication_slots;
|
||||||
slot_name
|
slot_name
|
||||||
-----------------------
|
------------------------
|
||||||
regression_slot_stats
|
regression_slot_stats1
|
||||||
(1 row)
|
regression_slot_stats2
|
||||||
|
regression_slot_stats3
|
||||||
|
(3 rows)
|
||||||
|
|
||||||
SELECT slot_name FROM pg_stat_replication_slots;
|
SELECT slot_name FROM pg_stat_replication_slots;
|
||||||
slot_name
|
slot_name
|
||||||
-----------------------
|
------------------------
|
||||||
regression_slot_stats
|
regression_slot_stats1
|
||||||
(1 row)
|
regression_slot_stats2
|
||||||
|
regression_slot_stats3
|
||||||
|
(3 rows)
|
||||||
|
|
||||||
COMMIT;
|
COMMIT;
|
||||||
DROP TABLE stats_test;
|
DROP TABLE stats_test;
|
||||||
SELECT pg_drop_replication_slot('regression_slot_stats');
|
SELECT pg_drop_replication_slot('regression_slot_stats1'),
|
||||||
pg_drop_replication_slot
|
pg_drop_replication_slot('regression_slot_stats2'),
|
||||||
--------------------------
|
pg_drop_replication_slot('regression_slot_stats3');
|
||||||
|
pg_drop_replication_slot | pg_drop_replication_slot | pg_drop_replication_slot
|
||||||
|
--------------------------+--------------------------+--------------------------
|
||||||
|
| |
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
|
@ -1,27 +1,41 @@
|
|||||||
-- predictability
|
-- predictability
|
||||||
SET synchronous_commit = on;
|
SET synchronous_commit = on;
|
||||||
|
|
||||||
SELECT 'init' FROM pg_create_logical_replication_slot('regression_slot_stats', 'test_decoding');
|
SELECT 'init' FROM
|
||||||
|
pg_create_logical_replication_slot('regression_slot_stats1', 'test_decoding') s1,
|
||||||
|
pg_create_logical_replication_slot('regression_slot_stats2', 'test_decoding') s2,
|
||||||
|
pg_create_logical_replication_slot('regression_slot_stats3', 'test_decoding') s3;
|
||||||
|
|
||||||
CREATE TABLE stats_test(data text);
|
CREATE TABLE stats_test(data text);
|
||||||
|
|
||||||
-- non-spilled xact
|
-- non-spilled xact
|
||||||
SET logical_decoding_work_mem to '64MB';
|
SET logical_decoding_work_mem to '64MB';
|
||||||
INSERT INTO stats_test values(1);
|
INSERT INTO stats_test values(1);
|
||||||
SELECT count(*) FROM pg_logical_slot_get_changes('regression_slot_stats', NULL, NULL, 'skip-empty-xacts', '1');
|
SELECT count(*) FROM pg_logical_slot_get_changes('regression_slot_stats1', NULL, NULL, 'skip-empty-xacts', '1');
|
||||||
|
SELECT count(*) FROM pg_logical_slot_get_changes('regression_slot_stats2', NULL, NULL, 'skip-empty-xacts', '1');
|
||||||
|
SELECT count(*) FROM pg_logical_slot_get_changes('regression_slot_stats3', NULL, NULL, 'skip-empty-xacts', '1');
|
||||||
SELECT pg_stat_force_next_flush();
|
SELECT pg_stat_force_next_flush();
|
||||||
SELECT slot_name, spill_txns = 0 AS spill_txns, spill_count = 0 AS spill_count, total_txns > 0 AS total_txns, total_bytes > 0 AS total_bytes FROM pg_stat_replication_slots;
|
SELECT slot_name, spill_txns = 0 AS spill_txns, spill_count = 0 AS spill_count, total_txns > 0 AS total_txns, total_bytes > 0 AS total_bytes FROM pg_stat_replication_slots ORDER BY slot_name;
|
||||||
RESET logical_decoding_work_mem;
|
RESET logical_decoding_work_mem;
|
||||||
|
|
||||||
-- reset the slot stats
|
-- reset stats for one slot, others should be unaffected
|
||||||
SELECT pg_stat_reset_replication_slot('regression_slot_stats');
|
SELECT pg_stat_reset_replication_slot('regression_slot_stats1');
|
||||||
SELECT slot_name, spill_txns, spill_count, total_txns, total_bytes FROM pg_stat_replication_slots;
|
SELECT slot_name, spill_txns = 0 AS spill_txns, spill_count = 0 AS spill_count, total_txns > 0 AS total_txns, total_bytes > 0 AS total_bytes FROM pg_stat_replication_slots ORDER BY slot_name;
|
||||||
|
|
||||||
|
-- reset stats for all slots
|
||||||
|
SELECT pg_stat_reset_replication_slot(NULL);
|
||||||
|
SELECT slot_name, spill_txns = 0 AS spill_txns, spill_count = 0 AS spill_count, total_txns > 0 AS total_txns, total_bytes > 0 AS total_bytes FROM pg_stat_replication_slots ORDER BY slot_name;
|
||||||
|
|
||||||
|
-- verify accessing/resetting stats for non-existent slot does something reasonable
|
||||||
|
SELECT * FROM pg_stat_get_replication_slot('do-not-exist');
|
||||||
|
SELECT pg_stat_reset_replication_slot('do-not-exist');
|
||||||
|
SELECT * FROM pg_stat_get_replication_slot('do-not-exist');
|
||||||
|
|
||||||
-- spilling the xact
|
-- spilling the xact
|
||||||
BEGIN;
|
BEGIN;
|
||||||
INSERT INTO stats_test SELECT 'serialize-topbig--1:'||g.i FROM generate_series(1, 5000) g(i);
|
INSERT INTO stats_test SELECT 'serialize-topbig--1:'||g.i FROM generate_series(1, 5000) g(i);
|
||||||
COMMIT;
|
COMMIT;
|
||||||
SELECT count(*) FROM pg_logical_slot_peek_changes('regression_slot_stats', NULL, NULL, 'skip-empty-xacts', '1');
|
SELECT count(*) FROM pg_logical_slot_peek_changes('regression_slot_stats1', NULL, NULL, 'skip-empty-xacts', '1');
|
||||||
|
|
||||||
-- Check stats. We can't test the exact stats count as that can vary if any
|
-- Check stats. We can't test the exact stats count as that can vary if any
|
||||||
-- background transaction (say by autovacuum) happens in parallel to the main
|
-- background transaction (say by autovacuum) happens in parallel to the main
|
||||||
@ -37,4 +51,6 @@ SELECT slot_name FROM pg_stat_replication_slots;
|
|||||||
COMMIT;
|
COMMIT;
|
||||||
|
|
||||||
DROP TABLE stats_test;
|
DROP TABLE stats_test;
|
||||||
SELECT pg_drop_replication_slot('regression_slot_stats');
|
SELECT pg_drop_replication_slot('regression_slot_stats1'),
|
||||||
|
pg_drop_replication_slot('regression_slot_stats2'),
|
||||||
|
pg_drop_replication_slot('regression_slot_stats3');
|
||||||
|
@ -200,6 +200,69 @@ chomp($logical_restart_lsn_post);
|
|||||||
ok(($logical_restart_lsn_pre cmp $logical_restart_lsn_post) == 0,
|
ok(($logical_restart_lsn_pre cmp $logical_restart_lsn_post) == 0,
|
||||||
"logical slot advance persists across restarts");
|
"logical slot advance persists across restarts");
|
||||||
|
|
||||||
|
my $stats_test_slot1 = 'test_slot';
|
||||||
|
my $stats_test_slot2 = 'logical_slot';
|
||||||
|
|
||||||
|
# Test that reset works for pg_stat_replication_slots
|
||||||
|
|
||||||
|
# Stats exist for stats test slot 1
|
||||||
|
is($node_primary->safe_psql(
|
||||||
|
'postgres',
|
||||||
|
qq(SELECT total_bytes > 0, stats_reset IS NULL FROM pg_stat_replication_slots WHERE slot_name = '$stats_test_slot1')
|
||||||
|
), qq(t|t), qq(Total bytes is > 0 and stats_reset is NULL for slot '$stats_test_slot1'.));
|
||||||
|
|
||||||
|
# Do reset of stats for stats test slot 1
|
||||||
|
$node_primary->safe_psql(
|
||||||
|
'postgres',
|
||||||
|
qq(SELECT pg_stat_reset_replication_slot('$stats_test_slot1'))
|
||||||
|
);
|
||||||
|
|
||||||
|
# Get reset value after reset
|
||||||
|
my $reset1 = $node_primary->safe_psql(
|
||||||
|
'postgres',
|
||||||
|
qq(SELECT stats_reset FROM pg_stat_replication_slots WHERE slot_name = '$stats_test_slot1')
|
||||||
|
);
|
||||||
|
|
||||||
|
# Do reset again
|
||||||
|
$node_primary->safe_psql(
|
||||||
|
'postgres',
|
||||||
|
qq(SELECT pg_stat_reset_replication_slot('$stats_test_slot1'))
|
||||||
|
);
|
||||||
|
|
||||||
|
is($node_primary->safe_psql(
|
||||||
|
'postgres',
|
||||||
|
qq(SELECT stats_reset > '$reset1'::timestamptz, total_bytes = 0 FROM pg_stat_replication_slots WHERE slot_name = '$stats_test_slot1')
|
||||||
|
), qq(t|t), qq(Check that reset timestamp is later after the second reset of stats for slot '$stats_test_slot1' and confirm total_bytes was set to 0.));
|
||||||
|
|
||||||
|
# Check that test slot 2 has NULL in reset timestamp
|
||||||
|
is($node_primary->safe_psql(
|
||||||
|
'postgres',
|
||||||
|
qq(SELECT stats_reset IS NULL FROM pg_stat_replication_slots WHERE slot_name = '$stats_test_slot2')
|
||||||
|
), qq(t), qq(Stats_reset is NULL for slot '$stats_test_slot2' before reset.));
|
||||||
|
|
||||||
|
# Get reset value again for test slot 1
|
||||||
|
$reset1 = $node_primary->safe_psql(
|
||||||
|
'postgres',
|
||||||
|
qq(SELECT stats_reset FROM pg_stat_replication_slots WHERE slot_name = '$stats_test_slot1')
|
||||||
|
);
|
||||||
|
|
||||||
|
# Reset stats for all replication slots
|
||||||
|
$node_primary->safe_psql(
|
||||||
|
'postgres',
|
||||||
|
qq(SELECT pg_stat_reset_replication_slot(NULL))
|
||||||
|
);
|
||||||
|
|
||||||
|
# Check that test slot 2 reset timestamp is no longer NULL after reset
|
||||||
|
is($node_primary->safe_psql(
|
||||||
|
'postgres',
|
||||||
|
qq(SELECT stats_reset IS NOT NULL FROM pg_stat_replication_slots WHERE slot_name = '$stats_test_slot2')
|
||||||
|
), qq(t), qq(Stats_reset is not NULL for slot '$stats_test_slot2' after reset all.));
|
||||||
|
|
||||||
|
is($node_primary->safe_psql(
|
||||||
|
'postgres',
|
||||||
|
qq(SELECT stats_reset > '$reset1'::timestamptz FROM pg_stat_replication_slots WHERE slot_name = '$stats_test_slot1')
|
||||||
|
), qq(t), qq(Check that reset timestamp is later after resetting stats for slot '$stats_test_slot1' again.));
|
||||||
|
|
||||||
# done with the node
|
# done with the node
|
||||||
$node_primary->stop;
|
$node_primary->stop;
|
||||||
|
|
||||||
|
@ -554,6 +554,170 @@ SELECT pg_stat_get_live_tuples(:drop_stats_test_subxact_oid);
|
|||||||
|
|
||||||
DROP TABLE trunc_stats_test, trunc_stats_test1, trunc_stats_test2, trunc_stats_test3, trunc_stats_test4;
|
DROP TABLE trunc_stats_test, trunc_stats_test1, trunc_stats_test2, trunc_stats_test3, trunc_stats_test4;
|
||||||
DROP TABLE prevstats;
|
DROP TABLE prevstats;
|
||||||
|
-----
|
||||||
|
-- Test that various stats views are being properly populated
|
||||||
|
-----
|
||||||
|
-- Test that sessions is incremented when a new session is started in pg_stat_database
|
||||||
|
SELECT sessions AS db_stat_sessions FROM pg_stat_database WHERE datname = (SELECT current_database()) \gset
|
||||||
|
\c
|
||||||
|
SELECT sessions > :db_stat_sessions FROM pg_stat_database WHERE datname = (SELECT current_database());
|
||||||
|
?column?
|
||||||
|
----------
|
||||||
|
t
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- Test pg_stat_bgwriter checkpointer-related stats, together with pg_stat_wal
|
||||||
|
SELECT checkpoints_req AS rqst_ckpts_before FROM pg_stat_bgwriter \gset
|
||||||
|
-- Test pg_stat_wal
|
||||||
|
SELECT wal_bytes AS wal_bytes_before FROM pg_stat_wal \gset
|
||||||
|
CREATE TABLE test_stats_temp AS SELECT 17;
|
||||||
|
DROP TABLE test_stats_temp;
|
||||||
|
-- Checkpoint twice: The checkpointer reports stats after reporting completion
|
||||||
|
-- of the checkpoint. But after a second checkpoint we'll see at least the
|
||||||
|
-- results of the first.
|
||||||
|
CHECKPOINT;
|
||||||
|
CHECKPOINT;
|
||||||
|
SELECT checkpoints_req > :rqst_ckpts_before FROM pg_stat_bgwriter;
|
||||||
|
?column?
|
||||||
|
----------
|
||||||
|
t
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT wal_bytes > :wal_bytes_before FROM pg_stat_wal;
|
||||||
|
?column?
|
||||||
|
----------
|
||||||
|
t
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-----
|
||||||
|
-- Test that resetting stats works for reset timestamp
|
||||||
|
-----
|
||||||
|
-- Test that reset_slru with a specified SLRU works.
|
||||||
|
SELECT stats_reset AS slru_commit_ts_reset_ts FROM pg_stat_slru WHERE name = 'CommitTs' \gset
|
||||||
|
SELECT stats_reset AS slru_notify_reset_ts FROM pg_stat_slru WHERE name = 'Notify' \gset
|
||||||
|
SELECT pg_stat_reset_slru('CommitTs');
|
||||||
|
pg_stat_reset_slru
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT stats_reset > :'slru_commit_ts_reset_ts'::timestamptz FROM pg_stat_slru WHERE name = 'CommitTs';
|
||||||
|
?column?
|
||||||
|
----------
|
||||||
|
t
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT stats_reset AS slru_commit_ts_reset_ts FROM pg_stat_slru WHERE name = 'CommitTs' \gset
|
||||||
|
-- Test that multiple SLRUs are reset when no specific SLRU provided to reset function
|
||||||
|
SELECT pg_stat_reset_slru(NULL);
|
||||||
|
pg_stat_reset_slru
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT stats_reset > :'slru_commit_ts_reset_ts'::timestamptz FROM pg_stat_slru WHERE name = 'CommitTs';
|
||||||
|
?column?
|
||||||
|
----------
|
||||||
|
t
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT stats_reset > :'slru_notify_reset_ts'::timestamptz FROM pg_stat_slru WHERE name = 'Notify';
|
||||||
|
?column?
|
||||||
|
----------
|
||||||
|
t
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- Test that reset_shared with archiver specified as the stats type works
|
||||||
|
SELECT stats_reset AS archiver_reset_ts FROM pg_stat_archiver \gset
|
||||||
|
SELECT pg_stat_reset_shared('archiver');
|
||||||
|
pg_stat_reset_shared
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT stats_reset > :'archiver_reset_ts'::timestamptz FROM pg_stat_archiver;
|
||||||
|
?column?
|
||||||
|
----------
|
||||||
|
t
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT stats_reset AS archiver_reset_ts FROM pg_stat_archiver \gset
|
||||||
|
-- Test that reset_shared with bgwriter specified as the stats type works
|
||||||
|
SELECT stats_reset AS bgwriter_reset_ts FROM pg_stat_bgwriter \gset
|
||||||
|
SELECT pg_stat_reset_shared('bgwriter');
|
||||||
|
pg_stat_reset_shared
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT stats_reset > :'bgwriter_reset_ts'::timestamptz FROM pg_stat_bgwriter;
|
||||||
|
?column?
|
||||||
|
----------
|
||||||
|
t
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT stats_reset AS bgwriter_reset_ts FROM pg_stat_bgwriter \gset
|
||||||
|
-- Test that reset_shared with wal specified as the stats type works
|
||||||
|
SELECT stats_reset AS wal_reset_ts FROM pg_stat_wal \gset
|
||||||
|
SELECT pg_stat_reset_shared('wal');
|
||||||
|
pg_stat_reset_shared
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT stats_reset > :'wal_reset_ts'::timestamptz FROM pg_stat_wal;
|
||||||
|
?column?
|
||||||
|
----------
|
||||||
|
t
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT stats_reset AS wal_reset_ts FROM pg_stat_wal \gset
|
||||||
|
-- Test that reset_shared with no specified stats type doesn't reset anything
|
||||||
|
SELECT pg_stat_reset_shared(NULL);
|
||||||
|
pg_stat_reset_shared
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT stats_reset = :'archiver_reset_ts'::timestamptz FROM pg_stat_archiver;
|
||||||
|
?column?
|
||||||
|
----------
|
||||||
|
t
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT stats_reset = :'bgwriter_reset_ts'::timestamptz FROM pg_stat_bgwriter;
|
||||||
|
?column?
|
||||||
|
----------
|
||||||
|
t
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT stats_reset = :'wal_reset_ts'::timestamptz FROM pg_stat_wal;
|
||||||
|
?column?
|
||||||
|
----------
|
||||||
|
t
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- Test that reset works for pg_stat_database
|
||||||
|
-- Since pg_stat_database stats_reset starts out as NULL, reset it once first so we have something to compare it to
|
||||||
|
SELECT pg_stat_reset();
|
||||||
|
pg_stat_reset
|
||||||
|
---------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT stats_reset AS db_reset_ts FROM pg_stat_database WHERE datname = (SELECT current_database()) \gset
|
||||||
|
SELECT pg_stat_reset();
|
||||||
|
pg_stat_reset
|
||||||
|
---------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT stats_reset > :'db_reset_ts'::timestamptz FROM pg_stat_database WHERE datname = (SELECT current_database());
|
||||||
|
?column?
|
||||||
|
----------
|
||||||
|
t
|
||||||
|
(1 row)
|
||||||
|
|
||||||
----
|
----
|
||||||
-- pg_stat_get_snapshot_timestamp behavior
|
-- pg_stat_get_snapshot_timestamp behavior
|
||||||
----
|
----
|
||||||
|
@ -123,6 +123,9 @@ test: plancache limit plpgsql copy2 temp domain rangefuncs prepare conversion tr
|
|||||||
|
|
||||||
# ----------
|
# ----------
|
||||||
# Another group of parallel tests
|
# Another group of parallel tests
|
||||||
|
#
|
||||||
|
# The stats test resets stats, so nothing else needing stats access can be in
|
||||||
|
# this group.
|
||||||
# ----------
|
# ----------
|
||||||
test: partition_join partition_prune reloptions hash_part indexing partition_aggregate partition_info tuplesort explain compression memoize stats
|
test: partition_join partition_prune reloptions hash_part indexing partition_aggregate partition_info tuplesort explain compression memoize stats
|
||||||
|
|
||||||
|
@ -286,6 +286,84 @@ SELECT pg_stat_get_live_tuples(:drop_stats_test_subxact_oid);
|
|||||||
DROP TABLE trunc_stats_test, trunc_stats_test1, trunc_stats_test2, trunc_stats_test3, trunc_stats_test4;
|
DROP TABLE trunc_stats_test, trunc_stats_test1, trunc_stats_test2, trunc_stats_test3, trunc_stats_test4;
|
||||||
DROP TABLE prevstats;
|
DROP TABLE prevstats;
|
||||||
|
|
||||||
|
|
||||||
|
-----
|
||||||
|
-- Test that various stats views are being properly populated
|
||||||
|
-----
|
||||||
|
|
||||||
|
-- Test that sessions is incremented when a new session is started in pg_stat_database
|
||||||
|
SELECT sessions AS db_stat_sessions FROM pg_stat_database WHERE datname = (SELECT current_database()) \gset
|
||||||
|
\c
|
||||||
|
SELECT sessions > :db_stat_sessions FROM pg_stat_database WHERE datname = (SELECT current_database());
|
||||||
|
|
||||||
|
-- Test pg_stat_bgwriter checkpointer-related stats, together with pg_stat_wal
|
||||||
|
SELECT checkpoints_req AS rqst_ckpts_before FROM pg_stat_bgwriter \gset
|
||||||
|
|
||||||
|
-- Test pg_stat_wal
|
||||||
|
SELECT wal_bytes AS wal_bytes_before FROM pg_stat_wal \gset
|
||||||
|
|
||||||
|
CREATE TABLE test_stats_temp AS SELECT 17;
|
||||||
|
DROP TABLE test_stats_temp;
|
||||||
|
|
||||||
|
-- Checkpoint twice: The checkpointer reports stats after reporting completion
|
||||||
|
-- of the checkpoint. But after a second checkpoint we'll see at least the
|
||||||
|
-- results of the first.
|
||||||
|
CHECKPOINT;
|
||||||
|
CHECKPOINT;
|
||||||
|
|
||||||
|
SELECT checkpoints_req > :rqst_ckpts_before FROM pg_stat_bgwriter;
|
||||||
|
SELECT wal_bytes > :wal_bytes_before FROM pg_stat_wal;
|
||||||
|
|
||||||
|
|
||||||
|
-----
|
||||||
|
-- Test that resetting stats works for reset timestamp
|
||||||
|
-----
|
||||||
|
|
||||||
|
-- Test that reset_slru with a specified SLRU works.
|
||||||
|
SELECT stats_reset AS slru_commit_ts_reset_ts FROM pg_stat_slru WHERE name = 'CommitTs' \gset
|
||||||
|
SELECT stats_reset AS slru_notify_reset_ts FROM pg_stat_slru WHERE name = 'Notify' \gset
|
||||||
|
SELECT pg_stat_reset_slru('CommitTs');
|
||||||
|
SELECT stats_reset > :'slru_commit_ts_reset_ts'::timestamptz FROM pg_stat_slru WHERE name = 'CommitTs';
|
||||||
|
SELECT stats_reset AS slru_commit_ts_reset_ts FROM pg_stat_slru WHERE name = 'CommitTs' \gset
|
||||||
|
|
||||||
|
-- Test that multiple SLRUs are reset when no specific SLRU provided to reset function
|
||||||
|
SELECT pg_stat_reset_slru(NULL);
|
||||||
|
SELECT stats_reset > :'slru_commit_ts_reset_ts'::timestamptz FROM pg_stat_slru WHERE name = 'CommitTs';
|
||||||
|
SELECT stats_reset > :'slru_notify_reset_ts'::timestamptz FROM pg_stat_slru WHERE name = 'Notify';
|
||||||
|
|
||||||
|
-- Test that reset_shared with archiver specified as the stats type works
|
||||||
|
SELECT stats_reset AS archiver_reset_ts FROM pg_stat_archiver \gset
|
||||||
|
SELECT pg_stat_reset_shared('archiver');
|
||||||
|
SELECT stats_reset > :'archiver_reset_ts'::timestamptz FROM pg_stat_archiver;
|
||||||
|
SELECT stats_reset AS archiver_reset_ts FROM pg_stat_archiver \gset
|
||||||
|
|
||||||
|
-- Test that reset_shared with bgwriter specified as the stats type works
|
||||||
|
SELECT stats_reset AS bgwriter_reset_ts FROM pg_stat_bgwriter \gset
|
||||||
|
SELECT pg_stat_reset_shared('bgwriter');
|
||||||
|
SELECT stats_reset > :'bgwriter_reset_ts'::timestamptz FROM pg_stat_bgwriter;
|
||||||
|
SELECT stats_reset AS bgwriter_reset_ts FROM pg_stat_bgwriter \gset
|
||||||
|
|
||||||
|
-- Test that reset_shared with wal specified as the stats type works
|
||||||
|
SELECT stats_reset AS wal_reset_ts FROM pg_stat_wal \gset
|
||||||
|
SELECT pg_stat_reset_shared('wal');
|
||||||
|
SELECT stats_reset > :'wal_reset_ts'::timestamptz FROM pg_stat_wal;
|
||||||
|
SELECT stats_reset AS wal_reset_ts FROM pg_stat_wal \gset
|
||||||
|
|
||||||
|
-- Test that reset_shared with no specified stats type doesn't reset anything
|
||||||
|
SELECT pg_stat_reset_shared(NULL);
|
||||||
|
SELECT stats_reset = :'archiver_reset_ts'::timestamptz FROM pg_stat_archiver;
|
||||||
|
SELECT stats_reset = :'bgwriter_reset_ts'::timestamptz FROM pg_stat_bgwriter;
|
||||||
|
SELECT stats_reset = :'wal_reset_ts'::timestamptz FROM pg_stat_wal;
|
||||||
|
|
||||||
|
-- Test that reset works for pg_stat_database
|
||||||
|
|
||||||
|
-- Since pg_stat_database stats_reset starts out as NULL, reset it once first so we have something to compare it to
|
||||||
|
SELECT pg_stat_reset();
|
||||||
|
SELECT stats_reset AS db_reset_ts FROM pg_stat_database WHERE datname = (SELECT current_database()) \gset
|
||||||
|
SELECT pg_stat_reset();
|
||||||
|
SELECT stats_reset > :'db_reset_ts'::timestamptz FROM pg_stat_database WHERE datname = (SELECT current_database());
|
||||||
|
|
||||||
|
|
||||||
----
|
----
|
||||||
-- pg_stat_get_snapshot_timestamp behavior
|
-- pg_stat_get_snapshot_timestamp behavior
|
||||||
----
|
----
|
||||||
|
@ -18,83 +18,255 @@ my $node_subscriber = PostgreSQL::Test::Cluster->new('subscriber');
|
|||||||
$node_subscriber->init(allows_streaming => 'logical');
|
$node_subscriber->init(allows_streaming => 'logical');
|
||||||
$node_subscriber->start;
|
$node_subscriber->start;
|
||||||
|
|
||||||
# Initial table setup on both publisher and subscriber. On subscriber we
|
|
||||||
# create the same tables but with primary keys. Also, insert some data that
|
|
||||||
# will conflict with the data replicated from publisher later.
|
|
||||||
$node_publisher->safe_psql(
|
|
||||||
'postgres',
|
|
||||||
qq[
|
|
||||||
BEGIN;
|
|
||||||
CREATE TABLE test_tab1 (a int);
|
|
||||||
INSERT INTO test_tab1 VALUES (1);
|
|
||||||
COMMIT;
|
|
||||||
]);
|
|
||||||
$node_subscriber->safe_psql(
|
|
||||||
'postgres',
|
|
||||||
qq[
|
|
||||||
BEGIN;
|
|
||||||
CREATE TABLE test_tab1 (a int primary key);
|
|
||||||
INSERT INTO test_tab1 VALUES (1);
|
|
||||||
COMMIT;
|
|
||||||
]);
|
|
||||||
|
|
||||||
# Setup publication.
|
sub create_sub_pub_w_errors
|
||||||
my $publisher_connstr = $node_publisher->connstr . ' dbname=postgres';
|
{
|
||||||
$node_publisher->safe_psql('postgres',
|
my ($node_publisher, $node_subscriber, $db, $table_name) = @_;
|
||||||
"CREATE PUBLICATION tap_pub FOR TABLE test_tab1;");
|
# Initial table setup on both publisher and subscriber. On subscriber we
|
||||||
|
# create the same tables but with primary keys. Also, insert some data that
|
||||||
|
# will conflict with the data replicated from publisher later.
|
||||||
|
$node_publisher->safe_psql(
|
||||||
|
$db,
|
||||||
|
qq[
|
||||||
|
BEGIN;
|
||||||
|
CREATE TABLE $table_name(a int);
|
||||||
|
INSERT INTO $table_name VALUES (1);
|
||||||
|
COMMIT;
|
||||||
|
]);
|
||||||
|
$node_subscriber->safe_psql(
|
||||||
|
$db,
|
||||||
|
qq[
|
||||||
|
BEGIN;
|
||||||
|
CREATE TABLE $table_name(a int primary key);
|
||||||
|
INSERT INTO $table_name VALUES (1);
|
||||||
|
COMMIT;
|
||||||
|
]);
|
||||||
|
|
||||||
|
# Set up publication.
|
||||||
|
my $pub_name = $table_name . '_pub';
|
||||||
|
my $publisher_connstr = $node_publisher->connstr . qq( dbname=$db);
|
||||||
|
|
||||||
|
$node_publisher->safe_psql($db,
|
||||||
|
qq(CREATE PUBLICATION $pub_name FOR TABLE $table_name));
|
||||||
|
|
||||||
|
# Create subscription. The tablesync for table on subscription will enter into
|
||||||
|
# infinite error loop due to violating the unique constraint.
|
||||||
|
my $sub_name = $table_name . '_sub';
|
||||||
|
$node_subscriber->safe_psql($db,
|
||||||
|
qq(CREATE SUBSCRIPTION $sub_name CONNECTION '$publisher_connstr' PUBLICATION $pub_name)
|
||||||
|
);
|
||||||
|
|
||||||
|
$node_publisher->wait_for_catchup($sub_name);
|
||||||
|
|
||||||
|
# Wait for the tablesync error to be reported.
|
||||||
|
$node_subscriber->poll_query_until(
|
||||||
|
$db,
|
||||||
|
qq[
|
||||||
|
SELECT sync_error_count > 0
|
||||||
|
FROM pg_stat_subscription_stats
|
||||||
|
WHERE subname = '$sub_name'
|
||||||
|
])
|
||||||
|
or die
|
||||||
|
qq(Timed out while waiting for tablesync errors for subscription '$sub_name');
|
||||||
|
|
||||||
|
# Truncate test_tab1 so that tablesync worker can continue.
|
||||||
|
$node_subscriber->safe_psql($db, qq(TRUNCATE $table_name));
|
||||||
|
|
||||||
|
# Wait for initial tablesync to finish.
|
||||||
|
$node_subscriber->poll_query_until(
|
||||||
|
$db,
|
||||||
|
qq[
|
||||||
|
SELECT count(1) = 1 FROM pg_subscription_rel
|
||||||
|
WHERE srrelid = '$table_name'::regclass AND srsubstate in ('r', 's')
|
||||||
|
])
|
||||||
|
or die
|
||||||
|
qq(Timed out while waiting for subscriber to synchronize data for table '$table_name'.);
|
||||||
|
|
||||||
|
# Check test table on the subscriber has one row.
|
||||||
|
my $result =
|
||||||
|
$node_subscriber->safe_psql($db, qq(SELECT a FROM $table_name));
|
||||||
|
is($result, qq(1), qq(Check that table '$table_name' now has 1 row.));
|
||||||
|
|
||||||
|
# Insert data to test table on the publisher, raising an error on the
|
||||||
|
# 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.
|
||||||
|
$node_subscriber->poll_query_until(
|
||||||
|
$db,
|
||||||
|
qq[
|
||||||
|
SELECT apply_error_count > 0
|
||||||
|
FROM pg_stat_subscription_stats
|
||||||
|
WHERE subname = '$sub_name'
|
||||||
|
])
|
||||||
|
or die
|
||||||
|
qq(Timed out while waiting for apply error for subscription '$sub_name');
|
||||||
|
|
||||||
|
# Truncate test table so that apply worker can continue.
|
||||||
|
$node_subscriber->safe_psql($db, qq(TRUNCATE $table_name));
|
||||||
|
|
||||||
|
return ($pub_name, $sub_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
my $db = 'postgres';
|
||||||
|
|
||||||
# There shouldn't be any subscription errors before starting logical replication.
|
# There shouldn't be any subscription errors before starting logical replication.
|
||||||
my $result = $node_subscriber->safe_psql('postgres',
|
my $result = $node_subscriber->safe_psql($db,
|
||||||
"SELECT count(1) FROM pg_stat_subscription_stats");
|
qq(SELECT count(1) FROM pg_stat_subscription_stats));
|
||||||
is($result, qq(0), 'check no subscription error');
|
is($result, qq(0),
|
||||||
|
'Check that there are no subscription errors before starting logical replication.'
|
||||||
# Create subscription. The tablesync for test_tab1 on tap_sub will enter into
|
|
||||||
# infinite error loop due to violating the unique constraint.
|
|
||||||
$node_subscriber->safe_psql('postgres',
|
|
||||||
"CREATE SUBSCRIPTION tap_sub CONNECTION '$publisher_connstr' PUBLICATION tap_pub;"
|
|
||||||
);
|
);
|
||||||
|
|
||||||
$node_publisher->wait_for_catchup('tap_sub');
|
# Create the publication and subscription with sync and apply errors
|
||||||
|
my $table1_name = 'test_tab1';
|
||||||
|
my ($pub1_name, $sub1_name) =
|
||||||
|
create_sub_pub_w_errors($node_publisher, $node_subscriber, $db,
|
||||||
|
$table1_name);
|
||||||
|
|
||||||
# Wait for the tablesync error to be reported.
|
# Apply and Sync errors are > 0 and reset timestamp is NULL
|
||||||
$node_subscriber->poll_query_until(
|
is( $node_subscriber->safe_psql(
|
||||||
'postgres',
|
$db,
|
||||||
qq[
|
qq(SELECT apply_error_count > 0,
|
||||||
SELECT sync_error_count > 0
|
sync_error_count > 0,
|
||||||
FROM pg_stat_subscription_stats
|
stats_reset IS NULL
|
||||||
WHERE subname = 'tap_sub'
|
FROM pg_stat_subscription_stats
|
||||||
]) or die "Timed out while waiting for tablesync error";
|
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'.)
|
||||||
|
);
|
||||||
|
|
||||||
# Truncate test_tab1 so that tablesync worker can continue.
|
# Reset a single subscription
|
||||||
$node_subscriber->safe_psql('postgres', "TRUNCATE test_tab1;");
|
$node_subscriber->safe_psql($db,
|
||||||
|
qq(SELECT pg_stat_reset_subscription_stats((SELECT subid FROM pg_stat_subscription_stats WHERE subname = '$sub1_name')))
|
||||||
|
);
|
||||||
|
|
||||||
# Wait for initial tablesync for test_tab1 to finish.
|
# Apply and Sync errors are 0 and stats reset is not NULL
|
||||||
$node_subscriber->poll_query_until(
|
is( $node_subscriber->safe_psql(
|
||||||
'postgres',
|
$db,
|
||||||
qq[
|
qq(SELECT apply_error_count = 0,
|
||||||
SELECT count(1) = 1 FROM pg_subscription_rel
|
sync_error_count = 0,
|
||||||
WHERE srrelid = 'test_tab1'::regclass AND srsubstate in ('r', 's')
|
stats_reset IS NOT NULL
|
||||||
]) or die "Timed out while waiting for subscriber to synchronize data";
|
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'.)
|
||||||
|
);
|
||||||
|
|
||||||
# Check test_tab1 on the subscriber has one row.
|
# Get reset timestamp
|
||||||
$result = $node_subscriber->safe_psql('postgres', "SELECT a FROM test_tab1");
|
my $reset_time1 = $node_subscriber->safe_psql($db,
|
||||||
is($result, qq(1), 'check the table has now row');
|
qq(SELECT stats_reset FROM pg_stat_subscription_stats WHERE subname = '$sub1_name')
|
||||||
|
);
|
||||||
|
|
||||||
# Insert data to test_tab1 on the publisher, raising an error on the subscriber
|
# Reset single sub again
|
||||||
# due to violation of the unique constraint on test_tab1.
|
$node_subscriber->safe_psql(
|
||||||
$node_publisher->safe_psql('postgres', "INSERT INTO test_tab1 VALUES (1)");
|
$db,
|
||||||
|
qq(SELECT pg_stat_reset_subscription_stats((SELECT subid FROM
|
||||||
|
pg_stat_subscription_stats WHERE subname = '$sub1_name')))
|
||||||
|
);
|
||||||
|
|
||||||
# Wait for the apply error to be reported.
|
# check reset timestamp is newer after reset
|
||||||
$node_subscriber->poll_query_until(
|
is( $node_subscriber->safe_psql(
|
||||||
'postgres',
|
$db,
|
||||||
qq[
|
qq(SELECT stats_reset > '$reset_time1'::timestamptz FROM
|
||||||
SELECT apply_error_count > 0
|
pg_stat_subscription_stats WHERE subname = '$sub1_name')
|
||||||
FROM pg_stat_subscription_stats
|
),
|
||||||
WHERE subname = 'tap_sub'
|
qq(t),
|
||||||
]) or die "Timed out while waiting for apply error";
|
qq(Check reset timestamp for '$sub1_name' is newer after second reset.));
|
||||||
|
|
||||||
|
# Make second subscription and publication
|
||||||
|
my $table2_name = 'test_tab2';
|
||||||
|
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
|
||||||
|
is( $node_subscriber->safe_psql(
|
||||||
|
$db,
|
||||||
|
qq(SELECT apply_error_count > 0,
|
||||||
|
sync_error_count > 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'.)
|
||||||
|
);
|
||||||
|
|
||||||
|
# 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
|
||||||
|
is( $node_subscriber->safe_psql(
|
||||||
|
$db,
|
||||||
|
qq(SELECT apply_error_count = 0,
|
||||||
|
sync_error_count = 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.)
|
||||||
|
);
|
||||||
|
|
||||||
|
is( $node_subscriber->safe_psql(
|
||||||
|
$db,
|
||||||
|
qq(SELECT apply_error_count = 0,
|
||||||
|
sync_error_count = 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.)
|
||||||
|
);
|
||||||
|
|
||||||
|
$reset_time1 = $node_subscriber->safe_psql($db,
|
||||||
|
qq(SELECT stats_reset FROM pg_stat_subscription_stats WHERE subname = '$sub1_name')
|
||||||
|
);
|
||||||
|
my $reset_time2 = $node_subscriber->safe_psql($db,
|
||||||
|
qq(SELECT stats_reset FROM pg_stat_subscription_stats WHERE subname = '$sub2_name')
|
||||||
|
);
|
||||||
|
|
||||||
|
# Reset all subscriptions
|
||||||
|
$node_subscriber->safe_psql($db,
|
||||||
|
qq(SELECT pg_stat_reset_subscription_stats(NULL)));
|
||||||
|
|
||||||
|
# check reset timestamp for sub1 is newer after reset
|
||||||
|
is( $node_subscriber->safe_psql(
|
||||||
|
$db,
|
||||||
|
qq(SELECT stats_reset > '$reset_time1'::timestamptz FROM
|
||||||
|
pg_stat_subscription_stats WHERE subname = '$sub1_name')
|
||||||
|
),
|
||||||
|
qq(t),
|
||||||
|
qq(Confirm that reset timestamp for '$sub1_name' is newer after second reset.)
|
||||||
|
);
|
||||||
|
|
||||||
|
# check reset timestamp for sub2 is newer after reset
|
||||||
|
is( $node_subscriber->safe_psql(
|
||||||
|
$db,
|
||||||
|
qq(SELECT stats_reset > '$reset_time2'::timestamptz FROM
|
||||||
|
pg_stat_subscription_stats WHERE subname = '$sub2_name')
|
||||||
|
),
|
||||||
|
qq(t),
|
||||||
|
qq(Confirm that reset timestamp for '$sub2_name' is newer after second reset.)
|
||||||
|
);
|
||||||
|
|
||||||
|
# Get subscription 1 oid
|
||||||
|
my $sub1_oid = $node_subscriber->safe_psql($db,
|
||||||
|
qq(SELECT oid FROM pg_subscription WHERE subname = '$sub1_name'));
|
||||||
|
|
||||||
|
# Drop subscription 1
|
||||||
|
$node_subscriber->safe_psql($db, qq(DROP SUBSCRIPTION $sub1_name));
|
||||||
|
|
||||||
|
# Subscription stats for sub1 should be gone
|
||||||
|
is( $node_subscriber->safe_psql(
|
||||||
|
$db, qq(SELECT pg_stat_have_stats('subscription', 0, $sub1_oid))),
|
||||||
|
qq(f),
|
||||||
|
qq(Subscription stats for subscription '$sub1_name' should be removed.));
|
||||||
|
|
||||||
# Truncate test_tab1 so that apply worker can continue.
|
|
||||||
$node_subscriber->safe_psql('postgres', "TRUNCATE test_tab1;");
|
|
||||||
|
|
||||||
$node_subscriber->stop('fast');
|
$node_subscriber->stop('fast');
|
||||||
$node_publisher->stop('fast');
|
$node_publisher->stop('fast');
|
||||||
|
Reference in New Issue
Block a user