diff --git a/contrib/auto_explain/expected/auto_explain_optimizer.out b/contrib/auto_explain/expected/auto_explain_optimizer.out index e1d3e334d95..1f469cc45fc 100644 --- a/contrib/auto_explain/expected/auto_explain_optimizer.out +++ b/contrib/auto_explain/expected/auto_explain_optimizer.out @@ -38,7 +38,7 @@ LOG: duration: 0.026 ms plan: Query Text: SELECT relname FROM pg_class WHERE relname='pg_class'; Index Only Scan using pg_class_relname_nsp_index on pg_class (cost=0.15..4.17 rows=1 width=64) (actual rows=1 loops=1) Index Cond: (relname = 'pg_class'::name) - Heap Fetches: 1 + Heap Fetches: 0 (slice0) Executor memory: 105K bytes. Memory used: 128000kB relname diff --git a/contrib/pax_storage/src/test/isolation2/input/autovacuum-analyze.source b/contrib/pax_storage/src/test/isolation2/input/autovacuum-analyze.source index 32e79cdd491..19187b107c2 100644 --- a/contrib/pax_storage/src/test/isolation2/input/autovacuum-analyze.source +++ b/contrib/pax_storage/src/test/isolation2/input/autovacuum-analyze.source @@ -178,7 +178,7 @@ SELECT count(*) FROM pg_statistic where starelid = 'autostatstbl'::regclass; select relpages, reltuples from pg_class where oid = 'autostatstbl'::regclass; -- expect analyze_count = 1, autoanalyze_count = 0, and n_mod_since_analyze = 1000 since ANALYZE executed -- in same transaction for the insert statement. -select analyze_count, autoanalyze_count, n_mod_since_analyze from pg_stat_all_tables_internal where relname = 'autostatstbl'; +select analyze_count, autoanalyze_count, n_mod_since_analyze from pg_stat_all_tables where relname = 'autostatstbl'; -- Wait until autovacuum is triggered SELECT gp_wait_until_triggered_fault('auto_vac_worker_after_report_activity', 1, 1); @@ -192,7 +192,7 @@ SELECT gp_inject_fault('analyze_finished_one_relation', 'reset', 1); -- we can see the auto-ANALYZE finished select relpages, reltuples from pg_class where oid = 'autostatstbl'::regclass; -- expect analyze_count = 1, autoanalyze_count = 1, and n_mod_since_analyze = 0 -select analyze_count, autoanalyze_count, n_mod_since_analyze from pg_stat_all_tables_internal where relname = 'autostatstbl'; +select analyze_count, autoanalyze_count, n_mod_since_analyze from pg_stat_all_tables where relname = 'autostatstbl'; -- Case 2 -- -- with auto_stats 'on_change' mode, the auto-ANALYZE still trigger @@ -211,7 +211,7 @@ SELECT gp_inject_fault('auto_vac_worker_after_report_activity', 'suspend', '', ' select relpages, reltuples from pg_class where oid = 'autostatstbl'::regclass; -- expect analyze_count = 2, autoanalyze_count = 1, and n_mod_since_analyze = 1000 since ANALYZE executed -- in same transaction for the insert statement. -select analyze_count, autoanalyze_count, n_mod_since_analyze from pg_stat_all_tables_internal where relname = 'autostatstbl'; +select analyze_count, autoanalyze_count, n_mod_since_analyze from pg_stat_all_tables where relname = 'autostatstbl'; -- Wait until autovacuum is triggered SELECT gp_wait_until_triggered_fault('auto_vac_worker_after_report_activity', 1, 1); @@ -225,7 +225,7 @@ SELECT gp_inject_fault('analyze_finished_one_relation', 'reset', 1); -- we can see the auto-ANALYZE finished, check statistic and analyze count select relpages, reltuples from pg_class where oid = 'autostatstbl'::regclass; -- expect analyze_count = 2, autoanalyze_count = 2, and n_mod_since_analyze = 0 -select analyze_count, autoanalyze_count, n_mod_since_analyze from pg_stat_all_tables_internal where relname = 'autostatstbl'; +select analyze_count, autoanalyze_count, n_mod_since_analyze from pg_stat_all_tables where relname = 'autostatstbl'; -- Case 3 -- @@ -244,7 +244,7 @@ SELECT gp_inject_fault('auto_vac_worker_after_report_activity', 'suspend', '', ' select relpages, reltuples from pg_class where oid = 'autostatstbl'::regclass; -- expect analyze_count = 2, autoanalyze_count = 2, and n_mod_since_analyze = 1000 since ANALYZE executed -- in same transaction for the insert statement. -select analyze_count, autoanalyze_count, n_mod_since_analyze from pg_stat_all_tables_internal where relname = 'autostatstbl'; +select analyze_count, autoanalyze_count, n_mod_since_analyze from pg_stat_all_tables where relname = 'autostatstbl'; -- Wait until autovacuum is triggered SELECT gp_wait_until_triggered_fault('auto_vac_worker_after_report_activity', 1, 1); @@ -258,7 +258,7 @@ SELECT gp_inject_fault('analyze_finished_one_relation', 'reset', 1); -- we can see the auto-ANALYZE finished, check statistic and analyze count select relpages, reltuples from pg_class where oid = 'autostatstbl'::regclass; -- expect analyze_count = 2, autoanalyze_count = 3, and n_mod_since_analyze = 0 since ANALYZE executed -select analyze_count, autoanalyze_count, n_mod_since_analyze from pg_stat_all_tables_internal where relname = 'autostatstbl'; +select analyze_count, autoanalyze_count, n_mod_since_analyze from pg_stat_all_tables where relname = 'autostatstbl'; -- Reset GUCs. ALTER SYSTEM RESET autovacuum_naptime; diff --git a/contrib/pax_storage/src/test/isolation2/output/autovacuum-analyze.source b/contrib/pax_storage/src/test/isolation2/output/autovacuum-analyze.source index 0c4b87746e4..dff55111b64 100644 --- a/contrib/pax_storage/src/test/isolation2/output/autovacuum-analyze.source +++ b/contrib/pax_storage/src/test/isolation2/output/autovacuum-analyze.source @@ -422,7 +422,7 @@ select relpages, reltuples from pg_class where oid = 'autostatstbl'::regclass; (1 row) -- expect analyze_count = 1, autoanalyze_count = 0, and n_mod_since_analyze = 1000 since ANALYZE executed -- in same transaction for the insert statement. -select analyze_count, autoanalyze_count, n_mod_since_analyze from pg_stat_all_tables_internal where relname = 'autostatstbl'; +select analyze_count, autoanalyze_count, n_mod_since_analyze from pg_stat_all_tables where relname = 'autostatstbl'; analyze_count | autoanalyze_count | n_mod_since_analyze ---------------+-------------------+--------------------- 1 | 0 | 1000 @@ -465,7 +465,7 @@ select relpages, reltuples from pg_class where oid = 'autostatstbl'::regclass; 1 | 1000 (1 row) -- expect analyze_count = 1, autoanalyze_count = 1, and n_mod_since_analyze = 0 -select analyze_count, autoanalyze_count, n_mod_since_analyze from pg_stat_all_tables_internal where relname = 'autostatstbl'; +select analyze_count, autoanalyze_count, n_mod_since_analyze from pg_stat_all_tables where relname = 'autostatstbl'; analyze_count | autoanalyze_count | n_mod_since_analyze ---------------+-------------------+--------------------- 1 | 1 | 0 @@ -502,7 +502,7 @@ select relpages, reltuples from pg_class where oid = 'autostatstbl'::regclass; (1 row) -- expect analyze_count = 2, autoanalyze_count = 1, and n_mod_since_analyze = 1000 since ANALYZE executed -- in same transaction for the insert statement. -select analyze_count, autoanalyze_count, n_mod_since_analyze from pg_stat_all_tables_internal where relname = 'autostatstbl'; +select analyze_count, autoanalyze_count, n_mod_since_analyze from pg_stat_all_tables where relname = 'autostatstbl'; analyze_count | autoanalyze_count | n_mod_since_analyze ---------------+-------------------+--------------------- 2 | 1 | 1000 @@ -545,7 +545,7 @@ select relpages, reltuples from pg_class where oid = 'autostatstbl'::regclass; 1 | 2000 (1 row) -- expect analyze_count = 2, autoanalyze_count = 2, and n_mod_since_analyze = 0 -select analyze_count, autoanalyze_count, n_mod_since_analyze from pg_stat_all_tables_internal where relname = 'autostatstbl'; +select analyze_count, autoanalyze_count, n_mod_since_analyze from pg_stat_all_tables where relname = 'autostatstbl'; analyze_count | autoanalyze_count | n_mod_since_analyze ---------------+-------------------+--------------------- 2 | 2 | 0 @@ -581,7 +581,7 @@ select relpages, reltuples from pg_class where oid = 'autostatstbl'::regclass; (1 row) -- expect analyze_count = 2, autoanalyze_count = 2, and n_mod_since_analyze = 1000 since ANALYZE executed -- in same transaction for the insert statement. -select analyze_count, autoanalyze_count, n_mod_since_analyze from pg_stat_all_tables_internal where relname = 'autostatstbl'; +select analyze_count, autoanalyze_count, n_mod_since_analyze from pg_stat_all_tables where relname = 'autostatstbl'; analyze_count | autoanalyze_count | n_mod_since_analyze ---------------+-------------------+--------------------- 2 | 2 | 1000 @@ -624,7 +624,7 @@ select relpages, reltuples from pg_class where oid = 'autostatstbl'::regclass; 1 | 3000 (1 row) -- expect analyze_count = 2, autoanalyze_count = 3, and n_mod_since_analyze = 0 since ANALYZE executed -select analyze_count, autoanalyze_count, n_mod_since_analyze from pg_stat_all_tables_internal where relname = 'autostatstbl'; +select analyze_count, autoanalyze_count, n_mod_since_analyze from pg_stat_all_tables where relname = 'autostatstbl'; analyze_count | autoanalyze_count | n_mod_since_analyze ---------------+-------------------+--------------------- 2 | 3 | 0 diff --git a/contrib/pax_storage/src/test/regress/expected/pg_stat.out b/contrib/pax_storage/src/test/regress/expected/pg_stat.out index 27dc25f957d..761372051ef 100644 --- a/contrib/pax_storage/src/test/regress/expected/pg_stat.out +++ b/contrib/pax_storage/src/test/regress/expected/pg_stat.out @@ -5,7 +5,7 @@ create table pg_stat_test(a int); select schemaname, relname, seq_scan, seq_tup_read, idx_scan, idx_tup_fetch, n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup -from pg_stat_all_tables where relname = 'pg_stat_test'; +from gp_stat_all_tables_summary where relname = 'pg_stat_test'; schemaname | relname | seq_scan | seq_tup_read | idx_scan | idx_tup_fetch | n_tup_ins | n_tup_upd | n_tup_del | n_tup_hot_upd | n_live_tup | n_dead_tup ------------+--------------+----------+--------------+----------+---------------+-----------+-----------+-----------+---------------+------------+------------ public | pg_stat_test | 0 | 0 | | | 0 | 0 | 0 | 0 | 0 | 0 @@ -14,7 +14,7 @@ from pg_stat_all_tables where relname = 'pg_stat_test'; select schemaname, relname, seq_scan, seq_tup_read, idx_scan, idx_tup_fetch, n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup -from pg_stat_user_tables where relname = 'pg_stat_test'; +from gp_stat_user_tables_summary where relname = 'pg_stat_test'; schemaname | relname | seq_scan | seq_tup_read | idx_scan | idx_tup_fetch | n_tup_ins | n_tup_upd | n_tup_del | n_tup_hot_upd | n_live_tup | n_dead_tup ------------+--------------+----------+--------------+----------+---------------+-----------+-----------+-----------+---------------+------------+------------ public | pg_stat_test | 0 | 0 | | | 0 | 0 | 0 | 0 | 0 | 0 @@ -22,14 +22,14 @@ from pg_stat_user_tables where relname = 'pg_stat_test'; select schemaname, relname, indexrelname, idx_scan, idx_tup_read, idx_tup_fetch -from pg_stat_all_indexes where relname = 'pg_stat_test'; +from gp_stat_all_indexes_summary where relname = 'pg_stat_test'; schemaname | relname | indexrelname | idx_scan | idx_tup_read | idx_tup_fetch ------------+---------+--------------+----------+--------------+--------------- (0 rows) select schemaname, relname, indexrelname, idx_scan, idx_tup_read, idx_tup_fetch -from pg_stat_user_indexes where relname = 'pg_stat_test'; +from gp_stat_user_indexes_summary where relname = 'pg_stat_test'; schemaname | relname | indexrelname | idx_scan | idx_tup_read | idx_tup_fetch ------------+---------+--------------+----------+--------------+--------------- (0 rows) @@ -63,7 +63,7 @@ reset enable_seqscan; select schemaname, relname, seq_scan, seq_tup_read, idx_scan, idx_tup_fetch, n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze -from pg_stat_all_tables where relname = 'pg_stat_test'; +from gp_stat_all_tables_summary where relname = 'pg_stat_test'; schemaname | relname | seq_scan | seq_tup_read | idx_scan | idx_tup_fetch | n_tup_ins | n_tup_upd | n_tup_del | n_tup_hot_upd | n_live_tup | n_dead_tup | n_mod_since_analyze ------------+--------------+----------+--------------+----------+---------------+-----------+-----------+-----------+---------------+------------+------------+--------------------- public | pg_stat_test | 15 | 391 | 1 | 0 | 110 | 0 | 19 | 0 | 91 | 19 | 129 @@ -72,7 +72,7 @@ from pg_stat_all_tables where relname = 'pg_stat_test'; select schemaname, relname, seq_scan, seq_tup_read, idx_scan, idx_tup_fetch, n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze -from pg_stat_user_tables where relname = 'pg_stat_test'; +from gp_stat_user_tables_summary where relname = 'pg_stat_test'; schemaname | relname | seq_scan | seq_tup_read | idx_scan | idx_tup_fetch | n_tup_ins | n_tup_upd | n_tup_del | n_tup_hot_upd | n_live_tup | n_dead_tup | n_mod_since_analyze ------------+--------------+----------+--------------+----------+---------------+-----------+-----------+-----------+---------------+------------+------------+--------------------- public | pg_stat_test | 15 | 391 | 1 | 0 | 110 | 0 | 19 | 0 | 91 | 19 | 129 @@ -80,7 +80,7 @@ from pg_stat_user_tables where relname = 'pg_stat_test'; select schemaname, relname, indexrelname, idx_scan, idx_tup_read, idx_tup_fetch -from pg_stat_all_indexes where relname = 'pg_stat_test'; +from gp_stat_all_indexes_summary where relname = 'pg_stat_test'; schemaname | relname | indexrelname | idx_scan | idx_tup_read | idx_tup_fetch ------------+--------------+--------------------------+----------+--------------+--------------- public | pg_stat_test | pg_stat_user_table_index | 1 | 1 | 0 @@ -88,7 +88,7 @@ from pg_stat_all_indexes where relname = 'pg_stat_test'; select schemaname, relname, indexrelname, idx_scan, idx_tup_read, idx_tup_fetch -from pg_stat_user_indexes where relname = 'pg_stat_test'; +from gp_stat_user_indexes_summary where relname = 'pg_stat_test'; schemaname | relname | indexrelname | idx_scan | idx_tup_read | idx_tup_fetch ------------+--------------+--------------------------+----------+--------------+--------------- public | pg_stat_test | pg_stat_user_table_index | 1 | 1 | 0 diff --git a/contrib/pax_storage/src/test/regress/expected/stats.out b/contrib/pax_storage/src/test/regress/expected/stats.out index d3f407656fc..a75f9801a36 100644 --- a/contrib/pax_storage/src/test/regress/expected/stats.out +++ b/contrib/pax_storage/src/test/regress/expected/stats.out @@ -22,7 +22,7 @@ SELECT t.seq_scan, t.seq_tup_read, t.idx_scan, t.idx_tup_fetch, (b.heap_blks_read + b.heap_blks_hit) AS heap_blks, (b.idx_blks_read + b.idx_blks_hit) AS idx_blks, pg_stat_get_snapshot_timestamp() as snap_ts - FROM pg_catalog.pg_stat_user_tables AS t, + FROM pg_catalog.gp_stat_user_tables_summary AS t, pg_catalog.pg_statio_user_tables AS b WHERE t.relname='tenk2' AND b.relname='tenk2'; -- function to wait for counters to advance @@ -45,17 +45,17 @@ begin -- check to see if seqscan has been sensed SELECT (st.seq_scan >= pr.seq_scan + 1) INTO updated1 - FROM pg_stat_user_tables AS st, pg_class AS cl, prevstats AS pr + FROM gp_stat_user_tables_summary AS st, pg_class AS cl, prevstats AS pr WHERE st.relname='tenk2' AND cl.relname='tenk2'; -- check to see if indexscan has been sensed SELECT (st.idx_scan >= pr.idx_scan + 1) INTO updated2 - FROM pg_stat_user_tables AS st, pg_class AS cl, prevstats AS pr + FROM gp_stat_user_tables_summary AS st, pg_class AS cl, prevstats AS pr WHERE st.relname='tenk2' AND cl.relname='tenk2'; -- check to see if all updates have been sensed SELECT (n_tup_ins > 0) INTO updated3 - FROM pg_stat_user_tables WHERE relname='trunc_stats_test4'; + FROM gp_stat_user_tables_summary WHERE relname='trunc_stats_test4'; -- We must also check explicitly that pg_stat_get_snapshot_timestamp has -- advanced, because that comes from the global stats file which might @@ -65,7 +65,7 @@ begin -- check to see if idx_tup_fetch has been sensed SELECT (st.idx_tup_fetch >= pr.idx_tup_fetch + 1) INTO updated5 - FROM pg_stat_user_tables AS st, pg_class AS cl, prevstats AS pr + FROM gp_stat_user_tables_summary AS st, pg_class AS cl, prevstats AS pr WHERE st.relname='tenk2' AND cl.relname='tenk2'; exit when updated1 and updated2 and updated3 and updated4 and updated5; @@ -177,7 +177,7 @@ SELECT wait_for_stats(); -- check effects SELECT relname, n_tup_ins, n_tup_upd, n_tup_del, n_live_tup, n_dead_tup - FROM pg_stat_user_tables + FROM gp_stat_user_tables_summary WHERE relname like 'trunc_stats_test%' order by relname; relname | n_tup_ins | n_tup_upd | n_tup_del | n_live_tup | n_dead_tup -------------------+-----------+-----------+-----------+------------+------------ @@ -192,7 +192,7 @@ SELECT st.seq_scan >= pr.seq_scan + 1, st.seq_tup_read >= pr.seq_tup_read + cl.reltuples, st.idx_scan >= pr.idx_scan + 1, st.idx_tup_fetch >= pr.idx_tup_fetch + 1 - FROM pg_stat_user_tables AS st, pg_class AS cl, prevstats AS pr + FROM gp_stat_user_tables_summary AS st, pg_class AS cl, prevstats AS pr WHERE st.relname='tenk2' AND cl.relname='tenk2'; ?column? | ?column? | ?column? | ?column? ----------+----------+----------+---------- diff --git a/contrib/pax_storage/src/test/regress/input/pgstat_qd_tabstat.source b/contrib/pax_storage/src/test/regress/input/pgstat_qd_tabstat.source index a3c201de66c..4be0a8c7eb8 100644 --- a/contrib/pax_storage/src/test/regress/input/pgstat_qd_tabstat.source +++ b/contrib/pax_storage/src/test/regress/input/pgstat_qd_tabstat.source @@ -10,7 +10,7 @@ copy table_for_docopy (i, j) from stdin; 3 hello3 \. select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'table_for_docopy'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables where relid = 'table_for_docopy'::regclass; CREATE TABLE data_tbl (a int,b char) distributed by (a); INSERT INTO data_tbl values(1,'1'); @@ -21,7 +21,7 @@ COPY data_tbl TO '/tmp/data_tbl.csv' on segment; create table copy_on_segment (a int,b char); COPY copy_on_segment from '/tmp/data_tbl.csv' on segment log errors segment reject limit 3 rows; select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'copy_on_segment'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables where relid = 'copy_on_segment'::regclass; -- Test pgstat table stat in initplan on QD @@ -34,26 +34,26 @@ copy table_for_initplan (i, j, k) from stdin; explain (costs off) with updated AS (update table_for_initplan set k = 33 where i = 3 returning k) select table_for_initplan.*, (select sum(k) from updated) from table_for_initplan; with updated AS (update table_for_initplan set k = 33 where i = 3 returning k) select table_for_initplan.*, (select sum(k) from updated) from table_for_initplan; select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'table_for_initplan'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables where relid = 'table_for_initplan'::regclass; -- Test pgstat table stat in CTAS on QD create table table_for_ctas as select i, 'hello' || i from generate_series(1, 100) f(i); select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'table_for_ctas'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables where relid = 'table_for_ctas'::regclass; select i, 'hello' || i into table_for_insert_into from generate_series(1, 100) f(i); select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'table_for_insert_into'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables where relid = 'table_for_insert_into'::regclass; -- Test pgstat table stat in ALTER TABLE SET DISTRIBUTED BY on QD create table table_for_set_distributed_by(i int, j varchar) distributed by (i); insert into table_for_set_distributed_by select i, 'hello' || i from generate_series(1, 333) f(i); select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'table_for_set_distributed_by'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables where relid = 'table_for_set_distributed_by'::regclass; alter table table_for_set_distributed_by set distributed by (j); select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'table_for_set_distributed_by'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables where relid = 'table_for_set_distributed_by'::regclass; -- Test pgstat table stat in execution of funciton on QD @@ -68,7 +68,7 @@ $$ language plpgsql volatile; select update_table_for_function(); select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'table_for_function'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables where relid = 'table_for_function'::regclass; -- Test pgstat table stat in ALTER TABLE EXPAND TABLE on QD; @@ -78,11 +78,11 @@ create table table_for_expand(i int, j varchar) distributed by (i); insert into table_for_expand select i, 'hello' || i from generate_series(1, 333) f(i); select count(distinct gp_segment_id) from table_for_expand; select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'table_for_expand'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables where relid = 'table_for_expand'::regclass; alter table table_for_expand expand table; select count(distinct gp_segment_id) from table_for_expand; select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'table_for_expand'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables where relid = 'table_for_expand'::regclass; select gp_debug_reset_create_table_default_numsegments(); @@ -103,7 +103,7 @@ update table_for_iud set j = 'heroes never die' where i >= 300; release savepoint level3; commit; select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. -select n_live_tup, n_dead_tup from pg_stat_all_tables_internal where relid = 'table_for_iud'::regclass; +select n_live_tup, n_dead_tup from pg_stat_all_tables where relid = 'table_for_iud'::regclass; begin; savepoint level1; @@ -120,14 +120,14 @@ rollback to savepoint level3; delete from table_for_iud where i <= 200; commit; select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. -select n_live_tup, n_dead_tup from pg_stat_all_tables_internal where relid = 'table_for_iud'::regclass; +select n_live_tup, n_dead_tup from pg_stat_all_tables where relid = 'table_for_iud'::regclass; -- Test pgstat table stat in TRUNCATE on QD create table table_for_truncate(i int, j varchar) distributed by (i); insert into table_for_truncate select i, 'hello' || i from generate_series(1, 777) f(i); select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'table_for_truncate'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables where relid = 'table_for_truncate'::regclass; begin; savepoint level1; savepoint level2; @@ -141,12 +141,12 @@ delete from table_for_truncate where i >= 700; update table_for_truncate set j = 'D' where i <= 200; commit; select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. -select n_live_tup, n_dead_tup from pg_stat_all_tables_internal where relid = 'table_for_truncate'::regclass; +select n_live_tup, n_dead_tup from pg_stat_all_tables where relid = 'table_for_truncate'::regclass; create table table_for_truncate_abort(i int, j varchar) distributed by (i); insert into table_for_truncate_abort select i, 'hello' || i from generate_series(1, 777) f(i); select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. -select n_live_tup, n_dead_tup from pg_stat_all_tables_internal where relid = 'table_for_truncate_abort'::regclass; +select n_live_tup, n_dead_tup from pg_stat_all_tables where relid = 'table_for_truncate_abort'::regclass; begin; savepoint level1; savepoint level2; @@ -160,7 +160,7 @@ delete from table_for_truncate_abort where i < 700; update table_for_truncate_abort set j = 'D' where i >= 200; rollback; select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. -select n_live_tup, n_dead_tup from pg_stat_all_tables_internal where relid = 'table_for_truncate_abort'::regclass; +select n_live_tup, n_dead_tup from pg_stat_all_tables where relid = 'table_for_truncate_abort'::regclass; -- Test pgstat table stat for partition table on QD @@ -171,17 +171,17 @@ PARTITION BY RANGE (rank) DEFAULT PARTITION extra ); insert into rankpart select i, i % 10, i from generate_series(1, 1000)i; select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'rankpart_1_prt_2'::regclass; -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'rankpart_1_prt_3'::regclass; -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'rankpart_1_prt_extra'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables where relid = 'rankpart_1_prt_2'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables where relid = 'rankpart_1_prt_3'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables where relid = 'rankpart_1_prt_extra'::regclass; begin; delete from rankpart where id <= 100; rollback; select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'rankpart_1_prt_2'::regclass; -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'rankpart_1_prt_3'::regclass; -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'rankpart_1_prt_extra'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables where relid = 'rankpart_1_prt_2'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables where relid = 'rankpart_1_prt_3'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables where relid = 'rankpart_1_prt_extra'::regclass; copy rankpart (id, rank, product) from stdin; 1001 1 1001 @@ -196,8 +196,8 @@ copy rankpart (id, rank, product) from stdin; 1010 6 1010 \. select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'rankpart_1_prt_2'::regclass; -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'rankpart_1_prt_3'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables where relid = 'rankpart_1_prt_2'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables where relid = 'rankpart_1_prt_3'::regclass; begin; update rankpart set rank = 1 where id > 1005; @@ -209,9 +209,9 @@ release savepoint level2; rollback to savepoint level1; commit; select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'rankpart_1_prt_2'::regclass; -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'rankpart_1_prt_3'::regclass; -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'rankpart_1_prt_extra'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables where relid = 'rankpart_1_prt_2'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables where relid = 'rankpart_1_prt_3'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables where relid = 'rankpart_1_prt_extra'::regclass; begin; savepoint level1_1; @@ -219,9 +219,9 @@ insert into rankpart select i, i % 10, i from generate_series(2001, 3000)i; insert into rankpart select i, i % 10, i from generate_series(3001, 4000)i; commit; select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'rankpart_1_prt_2'::regclass; -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'rankpart_1_prt_3'::regclass; -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'rankpart_1_prt_extra'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables where relid = 'rankpart_1_prt_2'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables where relid = 'rankpart_1_prt_3'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables where relid = 'rankpart_1_prt_extra'::regclass; -- Test pgstat matview stat with distributed policy. @@ -229,13 +229,13 @@ create table base_table(i int, j int, z int ) distributed by (i); insert into base_table select i,i,i from generate_series(1, 100) i; create materialized view mt as select * from base_table where z>=50; select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'mt'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables where relid = 'mt'::regclass; insert into base_table select i,i,i from generate_series(1, 100) i; refresh materialized view mt; select pg_sleep(0.77) from gp_dist_random('gp_id'); -- Force pgstat_report_stat() to send tabstat. -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'mt'::regclass; --- pg_stat_all_tables collects gpstats across segments select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables where relid = 'mt'::regclass; +-- gp_stat_all_tables_summary collects gpstats across segments +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from gp_stat_all_tables_summary where relid = 'mt'::regclass; drop materialized view mt; drop table base_table; @@ -245,13 +245,13 @@ create table base_table(i int, j int, z int ) distributed replicated; insert into base_table select i,i,i from generate_series(1, 100) i; create materialized view mt as select * from base_table where z>=50 distributed replicated; select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'mt'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables where relid = 'mt'::regclass; insert into base_table select i,i,i from generate_series(1, 100) i; refresh materialized view mt; select pg_sleep(0.77) from gp_dist_random('gp_id'); -- Force pgstat_report_stat() to send tabstat. -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'mt'::regclass; --- pg_stat_all_tables collects gpstats across segments select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables where relid = 'mt'::regclass; +-- gp_stat_all_tables_summary collects gpstats across segments +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from gp_stat_all_tables_summary where relid = 'mt'::regclass; reset gp_autostats_mode; @@ -263,15 +263,15 @@ insert into tabstat_ao select 1,1; delete from tabstat_ao; select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. -select count(*) from pg_stat_all_tables +select count(*) from gp_stat_all_tables_summary where relid = (select segrelid from pg_appendonly where relid = 'tabstat_ao'::regclass) OR relid = (select blkdirrelid from pg_appendonly where relid = 'tabstat_ao'::regclass) OR relid = (select visimaprelid from pg_appendonly where relid = 'tabstat_ao'::regclass); select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. -select n_tup_ins from pg_stat_all_tables where relid = (select segrelid from pg_appendonly where relid = 'tabstat_ao'::regclass); -select n_tup_ins from pg_stat_all_tables where relid = (select blkdirrelid from pg_appendonly where relid = 'tabstat_ao'::regclass); -select n_tup_ins from pg_stat_all_tables where relid = (select visimaprelid from pg_appendonly where relid = 'tabstat_ao'::regclass); +select n_tup_ins from gp_stat_all_tables_summary where relid = (select segrelid from pg_appendonly where relid = 'tabstat_ao'::regclass); +select n_tup_ins from gp_stat_all_tables_summary where relid = (select blkdirrelid from pg_appendonly where relid = 'tabstat_ao'::regclass); +select n_tup_ins from gp_stat_all_tables_summary where relid = (select visimaprelid from pg_appendonly where relid = 'tabstat_ao'::regclass); drop table tabstat_ao; diff --git a/contrib/pax_storage/src/test/regress/output/pgstat_qd_tabstat.source b/contrib/pax_storage/src/test/regress/output/pgstat_qd_tabstat.source index 5118839b171..a0b24ee35dc 100644 --- a/contrib/pax_storage/src/test/regress/output/pgstat_qd_tabstat.source +++ b/contrib/pax_storage/src/test/regress/output/pgstat_qd_tabstat.source @@ -10,7 +10,7 @@ select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. (1 row) -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'table_for_docopy'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables where relid = 'table_for_docopy'::regclass; n_tup_ins | n_tup_upd | n_tup_del | n_tup_hot_upd | n_live_tup | n_dead_tup | n_mod_since_analyze -----------+-----------+-----------+---------------+------------+------------+--------------------- 3 | 0 | 0 | 0 | 3 | 0 | 3 @@ -32,7 +32,7 @@ select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. (1 row) -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'copy_on_segment'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables where relid = 'copy_on_segment'::regclass; n_tup_ins | n_tup_upd | n_tup_del | n_tup_hot_upd | n_live_tup | n_dead_tup | n_mod_since_analyze -----------+-----------+-----------+---------------+------------+------------+--------------------- 4 | 0 | 0 | 0 | 4 | 0 | 4 @@ -70,7 +70,7 @@ select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. (1 row) -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'table_for_initplan'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables where relid = 'table_for_initplan'::regclass; n_tup_ins | n_tup_upd | n_tup_del | n_tup_hot_upd | n_live_tup | n_dead_tup | n_mod_since_analyze -----------+-----------+-----------+---------------+------------+------------+--------------------- 3 | 1 | 0 | 0 | 3 | 1 | 4 @@ -86,7 +86,7 @@ select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. (1 row) -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'table_for_ctas'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables where relid = 'table_for_ctas'::regclass; n_tup_ins | n_tup_upd | n_tup_del | n_tup_hot_upd | n_live_tup | n_dead_tup | n_mod_since_analyze -----------+-----------+-----------+---------------+------------+------------+--------------------- 100 | 0 | 0 | 0 | 100 | 0 | 100 @@ -101,7 +101,7 @@ select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. (1 row) -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'table_for_insert_into'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables where relid = 'table_for_insert_into'::regclass; n_tup_ins | n_tup_upd | n_tup_del | n_tup_hot_upd | n_live_tup | n_dead_tup | n_mod_since_analyze -----------+-----------+-----------+---------------+------------+------------+--------------------- 100 | 0 | 0 | 0 | 100 | 0 | 100 @@ -116,7 +116,7 @@ select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. (1 row) -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'table_for_set_distributed_by'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables where relid = 'table_for_set_distributed_by'::regclass; n_tup_ins | n_tup_upd | n_tup_del | n_tup_hot_upd | n_live_tup | n_dead_tup | n_mod_since_analyze -----------+-----------+-----------+---------------+------------+------------+--------------------- 333 | 0 | 0 | 0 | 333 | 0 | 333 @@ -129,7 +129,7 @@ select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. (1 row) -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'table_for_set_distributed_by'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables where relid = 'table_for_set_distributed_by'::regclass; n_tup_ins | n_tup_upd | n_tup_del | n_tup_hot_upd | n_live_tup | n_dead_tup | n_mod_since_analyze -----------+-----------+-----------+---------------+------------+------------+--------------------- 333 | 0 | 0 | 0 | 333 | 0 | 333 @@ -157,7 +157,7 @@ select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. (1 row) -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'table_for_function'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables where relid = 'table_for_function'::regclass; n_tup_ins | n_tup_upd | n_tup_del | n_tup_hot_upd | n_live_tup | n_dead_tup | n_mod_since_analyze -----------+-----------+-----------+---------------+------------+------------+--------------------- 333 | 0 | 200 | 0 | 133 | 200 | 533 @@ -185,7 +185,7 @@ select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. (1 row) -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'table_for_expand'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables where relid = 'table_for_expand'::regclass; n_tup_ins | n_tup_upd | n_tup_del | n_tup_hot_upd | n_live_tup | n_dead_tup | n_mod_since_analyze -----------+-----------+-----------+---------------+------------+------------+--------------------- 333 | 0 | 0 | 0 | 333 | 0 | 333 @@ -204,7 +204,7 @@ select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. (1 row) -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'table_for_expand'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables where relid = 'table_for_expand'::regclass; n_tup_ins | n_tup_upd | n_tup_del | n_tup_hot_upd | n_live_tup | n_dead_tup | n_mod_since_analyze -----------+-----------+-----------+---------------+------------+------------+--------------------- 333 | 0 | 0 | 0 | 333 | 0 | 333 @@ -238,7 +238,7 @@ select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. (1 row) -select n_live_tup, n_dead_tup from pg_stat_all_tables_internal where relid = 'table_for_iud'::regclass; +select n_live_tup, n_dead_tup from pg_stat_all_tables where relid = 'table_for_iud'::regclass; n_live_tup | n_dead_tup ------------+------------ 333 | 34 @@ -264,7 +264,7 @@ select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. (1 row) -select n_live_tup, n_dead_tup from pg_stat_all_tables_internal where relid = 'table_for_iud'::regclass; +select n_live_tup, n_dead_tup from pg_stat_all_tables where relid = 'table_for_iud'::regclass; n_live_tup | n_dead_tup ------------+------------ 133 | 713 @@ -279,7 +279,7 @@ select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. (1 row) -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'table_for_truncate'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables where relid = 'table_for_truncate'::regclass; n_tup_ins | n_tup_upd | n_tup_del | n_tup_hot_upd | n_live_tup | n_dead_tup | n_mod_since_analyze -----------+-----------+-----------+---------------+------------+------------+--------------------- 777 | 0 | 0 | 0 | 777 | 0 | 777 @@ -303,7 +303,7 @@ select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. (1 row) -select n_live_tup, n_dead_tup from pg_stat_all_tables_internal where relid = 'table_for_truncate'::regclass; +select n_live_tup, n_dead_tup from pg_stat_all_tables where relid = 'table_for_truncate'::regclass; n_live_tup | n_dead_tup ------------+------------ 699 | 301 @@ -317,7 +317,7 @@ select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. (1 row) -select n_live_tup, n_dead_tup from pg_stat_all_tables_internal where relid = 'table_for_truncate_abort'::regclass; +select n_live_tup, n_dead_tup from pg_stat_all_tables where relid = 'table_for_truncate_abort'::regclass; n_live_tup | n_dead_tup ------------+------------ 777 | 0 @@ -341,7 +341,7 @@ select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. (1 row) -select n_live_tup, n_dead_tup from pg_stat_all_tables_internal where relid = 'table_for_truncate_abort'::regclass; +select n_live_tup, n_dead_tup from pg_stat_all_tables where relid = 'table_for_truncate_abort'::regclass; n_live_tup | n_dead_tup ------------+------------ 777 | 223 @@ -360,19 +360,19 @@ select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. (1 row) -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'rankpart_1_prt_2'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables where relid = 'rankpart_1_prt_2'::regclass; n_tup_ins | n_tup_upd | n_tup_del | n_tup_hot_upd | n_live_tup | n_dead_tup | n_mod_since_analyze -----------+-----------+-----------+---------------+------------+------------+--------------------- 500 | 0 | 0 | 0 | 500 | 0 | 500 (1 row) -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'rankpart_1_prt_3'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables where relid = 'rankpart_1_prt_3'::regclass; n_tup_ins | n_tup_upd | n_tup_del | n_tup_hot_upd | n_live_tup | n_dead_tup | n_mod_since_analyze -----------+-----------+-----------+---------------+------------+------------+--------------------- 400 | 0 | 0 | 0 | 400 | 0 | 400 (1 row) -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'rankpart_1_prt_extra'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables where relid = 'rankpart_1_prt_extra'::regclass; n_tup_ins | n_tup_upd | n_tup_del | n_tup_hot_upd | n_live_tup | n_dead_tup | n_mod_since_analyze -----------+-----------+-----------+---------------+------------+------------+--------------------- 100 | 0 | 0 | 0 | 100 | 0 | 100 @@ -387,19 +387,19 @@ select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. (1 row) -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'rankpart_1_prt_2'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables where relid = 'rankpart_1_prt_2'::regclass; n_tup_ins | n_tup_upd | n_tup_del | n_tup_hot_upd | n_live_tup | n_dead_tup | n_mod_since_analyze -----------+-----------+-----------+---------------+------------+------------+--------------------- 500 | 0 | 50 | 0 | 500 | 0 | 500 (1 row) -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'rankpart_1_prt_3'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables where relid = 'rankpart_1_prt_3'::regclass; n_tup_ins | n_tup_upd | n_tup_del | n_tup_hot_upd | n_live_tup | n_dead_tup | n_mod_since_analyze -----------+-----------+-----------+---------------+------------+------------+--------------------- 400 | 0 | 40 | 0 | 400 | 0 | 400 (1 row) -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'rankpart_1_prt_extra'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables where relid = 'rankpart_1_prt_extra'::regclass; n_tup_ins | n_tup_upd | n_tup_del | n_tup_hot_upd | n_live_tup | n_dead_tup | n_mod_since_analyze -----------+-----------+-----------+---------------+------------+------------+--------------------- 100 | 0 | 10 | 0 | 100 | 0 | 100 @@ -412,13 +412,13 @@ select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. (1 row) -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'rankpart_1_prt_2'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables where relid = 'rankpart_1_prt_2'::regclass; n_tup_ins | n_tup_upd | n_tup_del | n_tup_hot_upd | n_live_tup | n_dead_tup | n_mod_since_analyze -----------+-----------+-----------+---------------+------------+------------+--------------------- 505 | 0 | 50 | 0 | 505 | 0 | 505 (1 row) -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'rankpart_1_prt_3'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables where relid = 'rankpart_1_prt_3'::regclass; n_tup_ins | n_tup_upd | n_tup_del | n_tup_hot_upd | n_live_tup | n_dead_tup | n_mod_since_analyze -----------+-----------+-----------+---------------+------------+------------+--------------------- 405 | 0 | 40 | 0 | 405 | 0 | 405 @@ -439,19 +439,19 @@ select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. (1 row) -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'rankpart_1_prt_2'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables where relid = 'rankpart_1_prt_2'::regclass; n_tup_ins | n_tup_upd | n_tup_del | n_tup_hot_upd | n_live_tup | n_dead_tup | n_mod_since_analyze -----------+-----------+-----------+---------------+------------+------------+--------------------- 510 | 0 | 55 | 0 | 510 | 0 | 510 (1 row) -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'rankpart_1_prt_3'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables where relid = 'rankpart_1_prt_3'::regclass; n_tup_ins | n_tup_upd | n_tup_del | n_tup_hot_upd | n_live_tup | n_dead_tup | n_mod_since_analyze -----------+-----------+-----------+---------------+------------+------------+--------------------- 410 | 0 | 50 | 0 | 400 | 10 | 410 (1 row) -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'rankpart_1_prt_extra'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables where relid = 'rankpart_1_prt_extra'::regclass; n_tup_ins | n_tup_upd | n_tup_del | n_tup_hot_upd | n_live_tup | n_dead_tup | n_mod_since_analyze -----------+-----------+-----------+---------------+------------+------------+--------------------- 100 | 0 | 10 | 0 | 100 | 0 | 100 @@ -468,19 +468,19 @@ select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. (1 row) -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'rankpart_1_prt_2'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables where relid = 'rankpart_1_prt_2'::regclass; n_tup_ins | n_tup_upd | n_tup_del | n_tup_hot_upd | n_live_tup | n_dead_tup | n_mod_since_analyze -----------+-----------+-----------+---------------+------------+------------+--------------------- 1510 | 0 | 55 | 0 | 1510 | 0 | 1510 (1 row) -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'rankpart_1_prt_3'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables where relid = 'rankpart_1_prt_3'::regclass; n_tup_ins | n_tup_upd | n_tup_del | n_tup_hot_upd | n_live_tup | n_dead_tup | n_mod_since_analyze -----------+-----------+-----------+---------------+------------+------------+--------------------- 1210 | 0 | 50 | 0 | 1200 | 10 | 1210 (1 row) -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'rankpart_1_prt_extra'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables where relid = 'rankpart_1_prt_extra'::regclass; n_tup_ins | n_tup_upd | n_tup_del | n_tup_hot_upd | n_live_tup | n_dead_tup | n_mod_since_analyze -----------+-----------+-----------+---------------+------------+------------+--------------------- 300 | 0 | 10 | 0 | 300 | 0 | 300 @@ -498,7 +498,7 @@ select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. (1 row) -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'mt'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables where relid = 'mt'::regclass; n_tup_ins | n_tup_upd | n_tup_del | n_tup_hot_upd | n_live_tup | n_dead_tup | n_mod_since_analyze -----------+-----------+-----------+---------------+------------+------------+--------------------- 51 | 0 | 0 | 0 | 51 | 0 | 51 @@ -514,14 +514,14 @@ select pg_sleep(0.77) from gp_dist_random('gp_id'); -- Force pgstat_report_stat( (3 rows) -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'mt'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables where relid = 'mt'::regclass; n_tup_ins | n_tup_upd | n_tup_del | n_tup_hot_upd | n_live_tup | n_dead_tup | n_mod_since_analyze -----------+-----------+-----------+---------------+------------+------------+--------------------- 153 | 0 | 0 | 0 | 102 | 0 | 153 (1 row) --- pg_stat_all_tables collects gpstats across segments -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables where relid = 'mt'::regclass; +-- gp_stat_all_tables_summary collects gpstats across segments +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from gp_stat_all_tables_summary where relid = 'mt'::regclass; n_tup_ins | n_tup_upd | n_tup_del | n_tup_hot_upd | n_live_tup | n_dead_tup | n_mod_since_analyze -----------+-----------+-----------+---------------+------------+------------+--------------------- 153 | 0 | 0 | 0 | 102 | 0 | 153 @@ -539,7 +539,7 @@ select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. (1 row) -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'mt'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables where relid = 'mt'::regclass; n_tup_ins | n_tup_upd | n_tup_del | n_tup_hot_upd | n_live_tup | n_dead_tup | n_mod_since_analyze -----------+-----------+-----------+---------------+------------+------------+--------------------- 51 | 0 | 0 | 0 | 51 | 0 | 51 @@ -555,14 +555,14 @@ select pg_sleep(0.77) from gp_dist_random('gp_id'); -- Force pgstat_report_stat( (3 rows) -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'mt'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables where relid = 'mt'::regclass; n_tup_ins | n_tup_upd | n_tup_del | n_tup_hot_upd | n_live_tup | n_dead_tup | n_mod_since_analyze -----------+-----------+-----------+---------------+------------+------------+--------------------- 153 | 0 | 0 | 0 | 102 | 0 | 153 (1 row) --- pg_stat_all_tables collects gpstats across segments -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables where relid = 'mt'::regclass; +-- gp_stat_all_tables_summary collects gpstats across segments +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from gp_stat_all_tables_summary where relid = 'mt'::regclass; n_tup_ins | n_tup_upd | n_tup_del | n_tup_hot_upd | n_live_tup | n_dead_tup | n_mod_since_analyze -----------+-----------+-----------+---------------+------------+------------+--------------------- 153 | 0 | 0 | 0 | 102 | 0 | 153 @@ -580,7 +580,7 @@ select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. (1 row) -select count(*) from pg_stat_all_tables +select count(*) from gp_stat_all_tables_summary where relid = (select segrelid from pg_appendonly where relid = 'tabstat_ao'::regclass) OR relid = (select blkdirrelid from pg_appendonly where relid = 'tabstat_ao'::regclass) @@ -596,19 +596,19 @@ select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. (1 row) -select n_tup_ins from pg_stat_all_tables where relid = (select segrelid from pg_appendonly where relid = 'tabstat_ao'::regclass); +select n_tup_ins from gp_stat_all_tables_summary where relid = (select segrelid from pg_appendonly where relid = 'tabstat_ao'::regclass); n_tup_ins ----------- 1 (1 row) -select n_tup_ins from pg_stat_all_tables where relid = (select blkdirrelid from pg_appendonly where relid = 'tabstat_ao'::regclass); +select n_tup_ins from gp_stat_all_tables_summary where relid = (select blkdirrelid from pg_appendonly where relid = 'tabstat_ao'::regclass); n_tup_ins ----------- 1 (1 row) -select n_tup_ins from pg_stat_all_tables where relid = (select visimaprelid from pg_appendonly where relid = 'tabstat_ao'::regclass); +select n_tup_ins from gp_stat_all_tables_summary where relid = (select visimaprelid from pg_appendonly where relid = 'tabstat_ao'::regclass); n_tup_ins ----------- 1 diff --git a/contrib/pax_storage/src/test/regress/sql/pg_stat.sql b/contrib/pax_storage/src/test/regress/sql/pg_stat.sql index d9fc37850b0..383a9149186 100644 --- a/contrib/pax_storage/src/test/regress/sql/pg_stat.sql +++ b/contrib/pax_storage/src/test/regress/sql/pg_stat.sql @@ -6,17 +6,17 @@ create table pg_stat_test(a int); select schemaname, relname, seq_scan, seq_tup_read, idx_scan, idx_tup_fetch, n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup -from pg_stat_all_tables where relname = 'pg_stat_test'; +from gp_stat_all_tables_summary where relname = 'pg_stat_test'; select schemaname, relname, seq_scan, seq_tup_read, idx_scan, idx_tup_fetch, n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup -from pg_stat_user_tables where relname = 'pg_stat_test'; +from gp_stat_user_tables_summary where relname = 'pg_stat_test'; select schemaname, relname, indexrelname, idx_scan, idx_tup_read, idx_tup_fetch -from pg_stat_all_indexes where relname = 'pg_stat_test'; +from gp_stat_all_indexes_summary where relname = 'pg_stat_test'; select schemaname, relname, indexrelname, idx_scan, idx_tup_read, idx_tup_fetch -from pg_stat_user_indexes where relname = 'pg_stat_test'; +from gp_stat_user_indexes_summary where relname = 'pg_stat_test'; begin; -- make analyze same transcation with insert to avoid double the pgstat causes by unorder message read. insert into pg_stat_test select * from generate_series(1, 100); @@ -42,17 +42,17 @@ reset enable_seqscan; select schemaname, relname, seq_scan, seq_tup_read, idx_scan, idx_tup_fetch, n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze -from pg_stat_all_tables where relname = 'pg_stat_test'; +from gp_stat_all_tables_summary where relname = 'pg_stat_test'; select schemaname, relname, seq_scan, seq_tup_read, idx_scan, idx_tup_fetch, n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze -from pg_stat_user_tables where relname = 'pg_stat_test'; +from gp_stat_user_tables_summary where relname = 'pg_stat_test'; select schemaname, relname, indexrelname, idx_scan, idx_tup_read, idx_tup_fetch -from pg_stat_all_indexes where relname = 'pg_stat_test'; +from gp_stat_all_indexes_summary where relname = 'pg_stat_test'; select schemaname, relname, indexrelname, idx_scan, idx_tup_read, idx_tup_fetch -from pg_stat_user_indexes where relname = 'pg_stat_test'; +from gp_stat_user_indexes_summary where relname = 'pg_stat_test'; reset optimizer; reset max_parallel_workers_per_gather; diff --git a/contrib/pax_storage/src/test/regress/sql/stats.sql b/contrib/pax_storage/src/test/regress/sql/stats.sql index 36878562f87..94944161be7 100644 --- a/contrib/pax_storage/src/test/regress/sql/stats.sql +++ b/contrib/pax_storage/src/test/regress/sql/stats.sql @@ -20,7 +20,7 @@ SELECT t.seq_scan, t.seq_tup_read, t.idx_scan, t.idx_tup_fetch, (b.heap_blks_read + b.heap_blks_hit) AS heap_blks, (b.idx_blks_read + b.idx_blks_hit) AS idx_blks, pg_stat_get_snapshot_timestamp() as snap_ts - FROM pg_catalog.pg_stat_user_tables AS t, + FROM pg_catalog.gp_stat_user_tables_summary AS t, pg_catalog.pg_statio_user_tables AS b WHERE t.relname='tenk2' AND b.relname='tenk2'; @@ -44,17 +44,17 @@ begin -- check to see if seqscan has been sensed SELECT (st.seq_scan >= pr.seq_scan + 1) INTO updated1 - FROM pg_stat_user_tables AS st, pg_class AS cl, prevstats AS pr + FROM gp_stat_user_tables_summary AS st, pg_class AS cl, prevstats AS pr WHERE st.relname='tenk2' AND cl.relname='tenk2'; -- check to see if indexscan has been sensed SELECT (st.idx_scan >= pr.idx_scan + 1) INTO updated2 - FROM pg_stat_user_tables AS st, pg_class AS cl, prevstats AS pr + FROM gp_stat_user_tables_summary AS st, pg_class AS cl, prevstats AS pr WHERE st.relname='tenk2' AND cl.relname='tenk2'; -- check to see if all updates have been sensed SELECT (n_tup_ins > 0) INTO updated3 - FROM pg_stat_user_tables WHERE relname='trunc_stats_test4'; + FROM gp_stat_user_tables_summary WHERE relname='trunc_stats_test4'; -- We must also check explicitly that pg_stat_get_snapshot_timestamp has -- advanced, because that comes from the global stats file which might @@ -64,7 +64,7 @@ begin -- check to see if idx_tup_fetch has been sensed SELECT (st.idx_tup_fetch >= pr.idx_tup_fetch + 1) INTO updated5 - FROM pg_stat_user_tables AS st, pg_class AS cl, prevstats AS pr + FROM gp_stat_user_tables_summary AS st, pg_class AS cl, prevstats AS pr WHERE st.relname='tenk2' AND cl.relname='tenk2'; exit when updated1 and updated2 and updated3 and updated4 and updated5; @@ -167,14 +167,14 @@ SELECT wait_for_stats(); -- check effects SELECT relname, n_tup_ins, n_tup_upd, n_tup_del, n_live_tup, n_dead_tup - FROM pg_stat_user_tables + FROM gp_stat_user_tables_summary WHERE relname like 'trunc_stats_test%' order by relname; SELECT st.seq_scan >= pr.seq_scan + 1, st.seq_tup_read >= pr.seq_tup_read + cl.reltuples, st.idx_scan >= pr.idx_scan + 1, st.idx_tup_fetch >= pr.idx_tup_fetch + 1 - FROM pg_stat_user_tables AS st, pg_class AS cl, prevstats AS pr + FROM gp_stat_user_tables_summary AS st, pg_class AS cl, prevstats AS pr WHERE st.relname='tenk2' AND cl.relname='tenk2'; -- GPDB_13_MERGE_FIXME: Some statistics are handled by stat collector process on each segment but not sent to master. diff --git a/src/backend/catalog/.gitignore b/src/backend/catalog/.gitignore index 6c4c6d228db..3912b022a03 100644 --- a/src/backend/catalog/.gitignore +++ b/src/backend/catalog/.gitignore @@ -8,3 +8,4 @@ /pg_*_d.h /gp_*_d.h /bki-stamp +/system_views_gp.sql diff --git a/src/backend/catalog/Makefile b/src/backend/catalog/Makefile index 666a861c6de..5679abf152a 100644 --- a/src/backend/catalog/Makefile +++ b/src/backend/catalog/Makefile @@ -59,6 +59,9 @@ OBJS += pg_extprotocol.o \ gp_matview_aux.o \ pg_directory_table.o storage_directory_table.o +GP_SYSVIEW_IN = system_views_gp.in +GP_SYSVIEW_SQL = system_views_gp.sql + CATALOG_JSON:= $(addprefix $(top_srcdir)/gpMgmt/bin/gppylib/data/, $(addsuffix .json,$(GP_MAJORVERSION))) include $(top_srcdir)/src/backend/common.mk @@ -136,7 +139,7 @@ POSTGRES_BKI_DATA += $(addprefix $(top_srcdir)/src/include/catalog/,\ $(top_builddir)/src/include/catalog/gp_version_at_initdb.dat -all: distprep generated-header-symlinks +all: distprep generated-header-symlinks $(GP_SYSVIEW_SQL) distprep: bki-stamp @@ -200,6 +203,8 @@ ifeq ($(USE_INTERNAL_FTS_FOUND), false) endif $(INSTALL_DATA) $(srcdir)/system_functions.sql '$(DESTDIR)$(datadir)/system_functions.sql' $(INSTALL_DATA) $(srcdir)/system_views.sql '$(DESTDIR)$(datadir)/system_views.sql' + $(INSTALL_DATA) $(srcdir)/$(GP_SYSVIEW_SQL) '$(DESTDIR)$(datadir)/$(GP_SYSVIEW_SQL)' + $(INSTALL_DATA) $(srcdir)/system_views_gp_summary.sql '$(DESTDIR)$(datadir)/system_views_gp_summary.sql' $(INSTALL_DATA) $(srcdir)/information_schema.sql '$(DESTDIR)$(datadir)/information_schema.sql' $(INSTALL_DATA) $(call vpathsearch,cdb_schema.sql) '$(DESTDIR)$(datadir)/cdb_init.d/cdb_schema.sql' $(INSTALL_DATA) $(srcdir)/sql_features.txt '$(DESTDIR)$(datadir)/sql_features.txt' @@ -211,7 +216,7 @@ installdirs: .PHONY: uninstall-data uninstall-data: - rm -f $(addprefix '$(DESTDIR)$(datadir)'/, postgres.bki system_constraints.sql system_functions.sql system_views.sql information_schema.sql cdb_init.d/cdb_schema.sql cdb_init.d/gp_toolkit.sql sql_features.txt fix-CVE-2024-4317.sql) + rm -f $(addprefix '$(DESTDIR)$(datadir)'/, postgres.bki system_constraints.sql system_functions.sql system_views.sql system_views_gp_summary.sql information_schema.sql cdb_init.d/cdb_schema.sql cdb_init.d/gp_toolkit.sql sql_features.txt fix-CVE-2024-4317.sql) ifeq ($(USE_INTERNAL_FTS_FOUND), false) rm -f $(addprefix '$(DESTDIR)$(datadir)'/, external_fts.sql) endif @@ -220,4 +225,4 @@ endif clean: maintainer-clean: clean - rm -f bki-stamp postgres.bki system_constraints.sql $(GENERATED_HEADERS) + rm -f bki-stamp postgres.bki system_constraints.sql $(GENERATED_HEADERS) $(GP_SYSVIEW_SQL) diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql index 8858c3ebcd5..505c817bc07 100644 --- a/src/backend/catalog/system_views.sql +++ b/src/backend/catalog/system_views.sql @@ -432,8 +432,7 @@ CREATE VIEW pg_prepared_xacts AS LEFT JOIN pg_database D ON P.dbid = D.oid; CREATE VIEW pg_prepared_statements AS - SELECT pg_catalog.gp_execution_segment() AS gp_segment_id, * - FROM pg_prepared_statement() AS P; + SELECT * FROM pg_prepared_statement() AS P; CREATE VIEW pg_seclabels AS SELECT @@ -665,8 +664,7 @@ REVOKE EXECUTE ON FUNCTION pg_get_shmem_allocations() FROM PUBLIC; GRANT EXECUTE ON FUNCTION pg_get_shmem_allocations() TO pg_read_all_stats; CREATE VIEW pg_backend_memory_contexts AS - SELECT pg_catalog.gp_execution_segment() AS gp_segment_id, * - FROM pg_get_backend_memory_contexts(); + SELECT * FROM pg_get_backend_memory_contexts(); REVOKE ALL ON pg_backend_memory_contexts FROM PUBLIC; GRANT SELECT ON pg_backend_memory_contexts TO pg_read_all_stats; @@ -675,7 +673,7 @@ GRANT EXECUTE ON FUNCTION pg_get_backend_memory_contexts() TO pg_read_all_stats; -- Statistics views -CREATE VIEW pg_stat_all_tables_internal AS +CREATE VIEW pg_stat_all_tables AS SELECT C.oid AS relid, N.nspname AS schemaname, @@ -710,87 +708,6 @@ CREATE VIEW pg_stat_all_tables_internal AS WHERE C.relkind IN ('r', 't', 'm', 'o', 'b', 'M', 'p') GROUP BY C.oid, N.nspname, C.relname; --- Gather data from segments on user tables, and use data on coordinator on system tables. - -CREATE VIEW pg_stat_all_tables AS -SELECT - s.relid, - s.schemaname, - s.relname, - m.seq_scan, - m.last_seq_scan, - m.seq_tup_read, - m.idx_scan, - m.last_idx_scan, - m.idx_tup_fetch, - m.n_tup_ins, - m.n_tup_upd, - m.n_tup_del, - m.n_tup_hot_upd, - m.n_tup_newpage_upd, - m.n_live_tup, - m.n_dead_tup, - m.n_mod_since_analyze, - m.n_ins_since_vacuum, - s.last_vacuum, - s.last_autovacuum, - s.last_analyze, - s.last_autoanalyze, - s.vacuum_count, - s.autovacuum_count, - s.analyze_count, - s.autoanalyze_count -FROM - (SELECT - allt.relid, - allt.schemaname, - allt.relname, - case when d.policytype = 'r' then (sum(seq_scan)/d.numsegments)::bigint else sum(seq_scan) end seq_scan, - max(last_seq_scan) as last_seq_scan, - case when d.policytype = 'r' then (sum(seq_tup_read)/d.numsegments)::bigint else sum(seq_tup_read) end seq_tup_read, - case when d.policytype = 'r' then (sum(idx_scan)/d.numsegments)::bigint else sum(idx_scan) end idx_scan, - max(last_idx_scan) as last_idx_scan, - case when d.policytype = 'r' then (sum(idx_tup_fetch)/d.numsegments)::bigint else sum(idx_tup_fetch) end idx_tup_fetch, - case when d.policytype = 'r' then (sum(n_tup_ins)/d.numsegments)::bigint else sum(n_tup_ins) end n_tup_ins, - case when d.policytype = 'r' then (sum(n_tup_upd)/d.numsegments)::bigint else sum(n_tup_upd) end n_tup_upd, - case when d.policytype = 'r' then (sum(n_tup_del)/d.numsegments)::bigint else sum(n_tup_del) end n_tup_del, - case when d.policytype = 'r' then (sum(n_tup_hot_upd)/d.numsegments)::bigint else sum(n_tup_hot_upd) end n_tup_hot_upd, - max(n_tup_newpage_upd) as n_tup_newpage_upd, - case when d.policytype = 'r' then (sum(n_live_tup)/d.numsegments)::bigint else sum(n_live_tup) end n_live_tup, - case when d.policytype = 'r' then (sum(n_dead_tup)/d.numsegments)::bigint else sum(n_dead_tup) end n_dead_tup, - case when d.policytype = 'r' then (sum(n_mod_since_analyze)/d.numsegments)::bigint else sum(n_mod_since_analyze) end n_mod_since_analyze, - case when d.policytype = 'r' then (sum(n_ins_since_vacuum)/d.numsegments)::bigint else sum(n_ins_since_vacuum) end n_ins_since_vacuum, - max(last_vacuum) as last_vacuum, - max(last_autovacuum) as last_autovacuum, - max(last_analyze) as last_analyze, - max(last_autoanalyze) as last_autoanalyze, - max(vacuum_count) as vacuum_count, - max(autovacuum_count) as autovacuum_count, - max(analyze_count) as analyze_count, - max(autoanalyze_count) as autoanalyze_count - FROM - gp_dist_random('pg_stat_all_tables_internal') allt - inner join pg_class c - on allt.relid = c.oid - left outer join gp_distribution_policy d - on allt.relid = d.localoid - WHERE - relid >= 16384 - and ( - d.localoid is not null - or c.relkind in ('o', 'b', 'M') - ) - GROUP BY allt.relid, allt.schemaname, allt.relname, d.policytype, d.numsegments - - UNION ALL - - SELECT - * - FROM - pg_stat_all_tables_internal - WHERE - relid < 16384) m, pg_stat_all_tables_internal s -WHERE m.relid = s.relid; CREATE VIEW pg_stat_xact_all_tables AS SELECT @@ -822,7 +739,7 @@ CREATE VIEW pg_stat_sys_tables AS -- since we don't have segments. -- We create a new view for single node mode. CREATE VIEW pg_stat_sys_tables_single_node AS - SELECT * FROM pg_stat_all_tables_internal + SELECT * FROM pg_stat_all_tables WHERE schemaname IN ('pg_catalog', 'information_schema') OR schemaname ~ '^pg_toast'; @@ -840,7 +757,7 @@ CREATE VIEW pg_stat_user_tables AS -- since we don't have segments. -- We create a new view for single node mode. CREATE VIEW pg_stat_user_tables_single_node AS - SELECT * FROM pg_stat_all_tables_internal + SELECT * FROM pg_stat_all_tables WHERE schemaname NOT IN ('pg_catalog', 'information_schema') AND schemaname !~ '^pg_toast'; @@ -893,7 +810,7 @@ CREATE VIEW pg_statio_user_tables AS WHERE schemaname NOT IN ('pg_catalog', 'information_schema') AND schemaname !~ '^pg_toast'; -CREATE VIEW pg_stat_all_indexes_internal AS +CREATE VIEW pg_stat_all_indexes AS SELECT C.oid AS relid, I.oid AS indexrelid, @@ -910,45 +827,6 @@ CREATE VIEW pg_stat_all_indexes_internal AS LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace) WHERE C.relkind IN ('r', 't', 'm', 'o', 'b', 'M'); --- Gather data from segments on user tables, and use data on coordinator on system tables. - -CREATE VIEW pg_stat_all_indexes AS -SELECT - s.relid, - s.indexrelid, - s.schemaname, - s.relname, - s.indexrelname, - m.idx_scan, - m.last_idx_scan, - m.idx_tup_read, - m.idx_tup_fetch -FROM - (SELECT - relid, - indexrelid, - schemaname, - relname, - indexrelname, - sum(idx_scan) as idx_scan, - max(last_idx_scan) as last_idx_scan, - sum(idx_tup_read) as idx_tup_read, - sum(idx_tup_fetch) as idx_tup_fetch - FROM - gp_dist_random('pg_stat_all_indexes_internal') - WHERE - relid >= 16384 - GROUP BY relid, indexrelid, schemaname, relname, indexrelname - - UNION ALL - - SELECT - * - FROM - pg_stat_all_indexes_internal - WHERE - relid < 16384) m, pg_stat_all_indexes_internal s -WHERE m.indexrelid = s.indexrelid; CREATE VIEW pg_stat_sys_indexes AS SELECT * FROM pg_stat_all_indexes @@ -1106,15 +984,6 @@ CREATE VIEW pg_stat_replication AS JOIN pg_stat_get_wal_senders() AS W ON (S.pid = W.pid) LEFT JOIN pg_authid AS U ON (S.usesysid = U.oid); --- FIXME: remove it after 0d0fdc75ae5b72d42be549e234a29546efe07ca2 -CREATE VIEW gp_stat_activity AS - SELECT gp_execution_segment() as gp_segment_id, * FROM gp_dist_random('pg_stat_activity') - UNION ALL SELECT -1 as gp_segment_id, * from pg_stat_activity; - -CREATE VIEW gp_settings AS - SELECT gp_execution_segment() as gp_segment_id, * FROM gp_dist_random('pg_settings') - UNION ALL SELECT -1 as gp_segment_id, * from pg_settings; - CREATE FUNCTION gp_stat_get_master_replication() RETURNS SETOF RECORD AS $$ SELECT pg_catalog.gp_execution_segment() AS gp_segment_id, * @@ -1135,6 +1004,7 @@ $$ $$ LANGUAGE SQL EXECUTE ON ALL SEGMENTS; +-- This view has an additional column than pg_stat_replication so cannot be generated using system_views_gp.in CREATE VIEW gp_stat_replication AS SELECT *, pg_catalog.gp_replication_error() AS sync_error FROM pg_catalog.gp_stat_get_master_replication() AS R @@ -1282,7 +1152,6 @@ CREATE VIEW pg_replication_slots AS CREATE VIEW pg_stat_replication_slots AS SELECT - pg_catalog.gp_execution_segment() AS gp_segment_id, s.slot_name, s.spill_txns, s.spill_count, @@ -1299,7 +1168,6 @@ CREATE VIEW pg_stat_replication_slots AS CREATE VIEW pg_stat_database AS SELECT - pg_catalog.gp_execution_segment() AS gp_segment_id, D.oid AS datid, D.datname AS datname, CASE @@ -1338,8 +1206,6 @@ CREATE VIEW pg_stat_database AS SELECT oid, datname FROM pg_database ) D; --- Resource queue views - CREATE VIEW pg_resqueue_status AS SELECT q.rsqname, @@ -1648,9 +1514,8 @@ FROM pg_stat_get_io() b; CREATE VIEW pg_stat_wal AS SELECT - pg_catalog.gp_execution_segment() AS gp_segment_id, w.wal_records, - w.wal_fpi, + w.wal_fpi as wal_fpw, w.wal_bytes, w.wal_buffers_full, w.wal_write, @@ -1662,7 +1527,6 @@ CREATE VIEW pg_stat_wal AS CREATE VIEW pg_stat_progress_analyze AS SELECT - pg_catalog.gp_execution_segment() AS gp_segment_id, S.pid AS pid, S.datid AS datid, D.datname AS datname, CAST(S.relid AS oid) AS relid, CASE S.param1 WHEN 0 THEN 'initializing' @@ -1684,7 +1548,6 @@ CREATE VIEW pg_stat_progress_analyze AS CREATE VIEW pg_stat_progress_vacuum AS SELECT - pg_catalog.gp_execution_segment() AS gp_segment_id, S.pid AS pid, S.datid AS datid, D.datname AS datname, S.relid AS relid, CASE S.param1 WHEN 0 THEN 'initializing' @@ -1706,7 +1569,6 @@ CREATE VIEW pg_stat_progress_vacuum AS CREATE VIEW pg_stat_progress_cluster AS SELECT - pg_catalog.gp_execution_segment() AS gp_segment_id, S.pid AS pid, S.datid AS datid, D.datname AS datname, @@ -1734,7 +1596,6 @@ CREATE VIEW pg_stat_progress_cluster AS CREATE VIEW pg_stat_progress_create_index AS SELECT - pg_catalog.gp_execution_segment() AS gp_segment_id, S.pid AS pid, S.datid AS datid, D.datname AS datname, S.relid AS relid, CAST(S.param7 AS oid) AS index_relid, @@ -1770,7 +1631,6 @@ CREATE VIEW pg_stat_progress_create_index AS CREATE VIEW pg_stat_progress_basebackup AS SELECT - pg_catalog.gp_execution_segment() AS gp_segment_id, S.pid AS pid, CASE S.param1 WHEN 0 THEN 'initializing' WHEN 1 THEN 'waiting for checkpoint to finish' @@ -1788,7 +1648,6 @@ CREATE VIEW pg_stat_progress_basebackup AS CREATE VIEW pg_stat_progress_copy AS SELECT - pg_catalog.gp_execution_segment() AS gp_segment_id, S.pid AS pid, S.datid AS datid, D.datname AS datname, S.relid AS relid, CASE S.param5 WHEN 1 THEN 'COPY FROM' @@ -1879,11 +1738,6 @@ UNION ALL SELECT gp_segment_id, gp_get_suboverflowed_backends() FROM gp_dist_random('gp_id') order by 1; -CREATE OR REPLACE VIEW gp_stat_archiver AS - SELECT -1 AS gp_segment_id, * FROM pg_stat_archiver - UNION - SELECT gp_execution_segment() AS gp_segment_id, * FROM gp_dist_random('pg_stat_archiver'); - CREATE FUNCTION gp_get_session_endpoints (OUT gp_segment_id int, OUT auth_token text, OUT cursorname text, OUT sessionid int, OUT hostname varchar(64), OUT port int, OUT username text, OUT state text, @@ -1967,3 +1821,94 @@ CREATE VIEW relation_tag_descriptions AS pg_namespace AS ns WHERE td.tagid = t.oid AND td.tdobjid = c.oid AND td.tddatabaseid = d.oid AND ns.oid = c.relnamespace; + +CREATE FUNCTION gp_stat_get_snapshot_timestamp() RETURNS timestamptz AS +$$ + SELECT MAX(pg_stat_get_snapshot_timestamp) as gp_stat_get_snapshot_timestamp + FROM + ( + SELECT pg_stat_get_snapshot_timestamp() + UNION ALL + SELECT pg_stat_get_snapshot_timestamp() FROM gp_dist_random('gp_id') + ) + WHERE pg_stat_get_snapshot_timestamp IS NOT NULL; +$$ +LANGUAGE SQL; + +CREATE FUNCTION gp_stat_force_next_flush() RETURNS VOID AS +$$ + SELECT pg_stat_force_next_flush() + UNION ALL + SELECT pg_stat_force_next_flush() FROM gp_dist_random('gp_id'); +$$ +LANGUAGE SQL; + +CREATE FUNCTION gp_stat_reset(tableoid oid) RETURNS VOID AS +$$ + SELECT pg_stat_reset() + UNION ALL + SELECT pg_stat_reset() FROM gp_dist_random('gp_id'); +$$ LANGUAGE SQL; + +CREATE FUNCTION gp_stat_reset_shared(target text) RETURNS VOID AS +$$ + SELECT pg_stat_reset_shared(target) + UNION ALL + SELECT pg_stat_reset_shared(target) FROM gp_dist_random('gp_id'); +$$ LANGUAGE SQL; + +CREATE FUNCTION gp_stat_reset_single_table_counters(tableoid oid) RETURNS VOID AS +$$ + WITH table_info AS ( + SELECT tableoid::regclass::text AS v_relname + ) + SELECT pg_stat_reset_single_table_counters(v_relname::regclass) + FROM table_info + UNION ALL + SELECT pg_stat_reset_single_table_counters(v_relname::regclass) + FROM table_info, gp_dist_random('gp_id'); +$$ LANGUAGE SQL; + +CREATE FUNCTION gp_stat_reset_single_function_counters(funcoid oid) RETURNS VOID AS +$$ + WITH func_info AS ( + SELECT proname FROM pg_proc WHERE oid = funcoid + ) + SELECT pg_stat_reset_single_function_counters(funcoid) + UNION ALL + SELECT ( + SELECT pg_stat_reset_single_function_counters(pg_proc.oid) + FROM pg_proc, func_info + WHERE pg_proc.proname = func_info.proname + ) + from gp_dist_random('gp_id'); +$$ LANGUAGE SQL; + +CREATE FUNCTION gp_stat_reset_slru(target text) RETURNS VOID AS +$$ + SELECT pg_stat_reset_slru(target) + UNION ALL + SELECT pg_stat_reset_slru(target) FROM gp_dist_random('gp_id'); +$$ LANGUAGE SQL; + +CREATE FUNCTION gp_stat_reset_replication_slot(target text) RETURNS VOID AS +$$ + SELECT pg_stat_reset_replication_slot(target) + UNION ALL + SELECT pg_stat_reset_replication_slot(target) FROM gp_dist_random('gp_id'); +$$ LANGUAGE SQL; + +CREATE FUNCTION gp_stat_reset_subscription_stats(subid oid) RETURNS VOID AS +$$ + WITH sub_info AS ( + SELECT subname FROM pg_subscription WHERE oid = subid + ) + SELECT pg_stat_reset_single_function_counters(subid) + UNION ALL + SELECT ( + SELECT pg_stat_reset_single_function_counters(pg_subscription.oid) + FROM pg_subscription, sub_info + WHERE pg_subscription.subname = sub_info.subname + ) + from gp_dist_random('gp_id'); +$$ LANGUAGE SQL; \ No newline at end of file diff --git a/src/backend/catalog/system_views_gp.in b/src/backend/catalog/system_views_gp.in new file mode 100644 index 00000000000..d3ddc5c60a5 --- /dev/null +++ b/src/backend/catalog/system_views_gp.in @@ -0,0 +1,49 @@ +# This file lists all the PG system views 'pg_%' that we would like to create an +# MPP-aware view 'gp_%' out of. The generated 'gp_%' view definitions will be placed +# in system_views_gp.sql, and initialized at the same time as system_views.sql. +pg_backend_memory_contexts +pg_config +pg_cursors +pg_file_settings +pg_replication_origin_status +pg_replication_slots +pg_settings +pg_stat_activity +pg_stat_archiver +pg_stat_bgwriter +pg_stat_database +pg_stat_database_conflicts +pg_stat_gssapi +pg_stat_operations +pg_stat_progress_analyze +pg_stat_progress_basebackup +pg_stat_progress_cluster +pg_stat_progress_copy +pg_stat_progress_create_index +pg_stat_progress_vacuum +pg_stat_slru +pg_stat_ssl +pg_stat_subscription +pg_stat_sys_indexes +pg_stat_sys_tables +pg_stat_user_functions +pg_stat_user_indexes +pg_stat_user_tables +pg_stat_wal +pg_stat_wal_receiver +pg_stat_xact_all_tables +pg_stat_xact_sys_tables +pg_stat_xact_user_functions +pg_stat_xact_user_tables +pg_statio_all_indexes +pg_statio_all_sequences +pg_statio_all_tables +pg_statio_sys_indexes +pg_statio_sys_sequences +pg_statio_sys_tables +pg_statio_user_indexes +pg_statio_user_sequences +pg_statio_user_tables +pg_stats +pg_stats_ext +pg_stat_io \ No newline at end of file diff --git a/src/backend/catalog/system_views_gp_summary.sql b/src/backend/catalog/system_views_gp_summary.sql new file mode 100644 index 00000000000..62bde4e3d96 --- /dev/null +++ b/src/backend/catalog/system_views_gp_summary.sql @@ -0,0 +1,522 @@ +/* + * Greenplum System Summary Views + * + * Portions Copyright (c) 2006-2010, Greenplum inc. + * Portions Copyright (c) 2012-Present VMware, Inc. or its affiliates. + * Copyright (c) 1996-2019, PostgreSQL Global Development Group + * + * src/backend/catalog/system_views_gp_summary.sql + * + + * This file contains summary views for various Greenplum system catalog + * views. These summary views are designed to provide aggregated or averaged + * information for partitioned and replicated tables, considering multiple + * segments in a Greenplum database. + * + * Note: this file is read in single-user -j mode, which means that the + * command terminator is semicolon-newline-newline; whenever the backend + * sees that, it stops and executes what it's got. If you write a lot of + * statements without empty lines between, they'll all get quoted to you + * in any error message about one of them, so don't do that. Also, you + * cannot write a semicolon immediately followed by an empty line in a + * string literal (including a function body!) or a multiline comment. + */ + +CREATE VIEW gp_stat_archiver_summary AS +SELECT + sum(gsa.archived_count) as archived_count, + max(gsa.last_archived_wal) as last_archived_wal, + max(gsa.last_archived_time) as last_archived_time, + sum(gsa.failed_count) as failed_count, + max(gsa.last_failed_wal) as last_failed_wal, + max(gsa.last_failed_time) as last_failed_time, + max(gsa.stats_reset) as stats_reset +FROM + gp_stat_archiver gsa; + +CREATE VIEW gp_stat_bgwriter_summary AS +SELECT + sum(gsb.checkpoints_timed) as checkpoints_timed, + sum(gsb.checkpoints_req) as checkpoints_req, + sum(gsb.checkpoint_write_time) as checkpoint_write_time, + sum(gsb.checkpoint_sync_time) as checkpoint_sync_time, + sum(gsb.buffers_checkpoint) as buffers_checkpoint, + sum(gsb.buffers_clean) as buffers_clean, + sum(gsb.maxwritten_clean) as maxwritten_clean, + sum(gsb.buffers_backend) as buffers_backend, + sum(gsb.buffers_backend_fsync) as buffers_backend_fsync, + sum(gsb.buffers_alloc) as buffers_alloc, + max(gsb.stats_reset) as stats_reset +FROM + gp_stat_bgwriter gsb; + +CREATE VIEW gp_stat_wal_summary AS +SELECT + sum(gsw.wal_records) as wal_records, + sum(gsw.wal_fpw) as wal_fpw, + sum(gsw.wal_bytes) as wal_bytes, + sum(gsw.wal_buffers_full) as wal_buffers_full, + sum(gsw.wal_write) as wal_write, + sum(gsw.wal_sync) as wal_sync, + sum(gsw.wal_write_time) as wal_write_time, + sum(gsw.wal_sync_time) as wal_sync_time, + max(gsw.stats_reset) as stats_reset +from + gp_stat_wal gsw; + +CREATE VIEW gp_stat_database_summary AS +SELECT + sdb.datid, + sdb.datname, + sum(sdb.numbackends) as numbackends, + max(sdb.xact_commit) as xact_commit, + max(sdb.xact_rollback) as xact_rollback, + sum(sdb.blks_read) as blks_read, + sum(sdb.blks_hit) as blks_hit, + sum(sdb.tup_returned) as tup_returned, + sum(sdb.tup_fetched) as tup_fetched, + sum(sdb.tup_inserted) as tup_inserted, + sum(sdb.tup_updated) as tup_updated, + sum(sdb.tup_deleted) as tup_deleted, + max(sdb.conflicts) as conflicts, + sum(sdb.temp_files) as temp_files, + sum(sdb.temp_bytes) as temp_bytes, + sum(sdb.deadlocks) as deadlocks, + sum(sdb.checksum_failures) as checksum_failures, + max(sdb.checksum_last_failure) as checksum_last_failure, + sum(sdb.blk_read_time) as blk_read_time, + sum(sdb.blk_write_time) as blk_write_time, + max(sdb.stats_reset) as stats_reset +FROM + gp_stat_database sdb +GROUP BY + sdb.datid, + sdb.datname; + + +-- Gather data from segments on user tables, and use data on coordinator on system tables. +CREATE VIEW gp_stat_all_tables_summary AS +SELECT + s.relid, + s.schemaname, + s.relname, + m.seq_scan, + m.last_seq_scan, + m.seq_tup_read, + m.idx_scan, + m.last_idx_scan, + m.idx_tup_fetch, + m.n_tup_ins, + m.n_tup_upd, + m.n_tup_del, + m.n_tup_hot_upd, + m.n_live_tup, + m.n_dead_tup, + m.n_mod_since_analyze, + s.last_vacuum, + s.last_autovacuum, + s.last_analyze, + s.last_autoanalyze, + s.vacuum_count, + s.autovacuum_count, + s.analyze_count, + s.autoanalyze_count +FROM + (SELECT + allt.relid, + allt.schemaname, + allt.relname, + case when d.policytype = 'r' then (sum(seq_scan)/d.numsegments)::bigint else sum(seq_scan) end seq_scan, + max(last_seq_scan) as last_seq_scan, + case when d.policytype = 'r' then (sum(seq_tup_read)/d.numsegments)::bigint else sum(seq_tup_read) end seq_tup_read, + case when d.policytype = 'r' then (sum(idx_scan)/d.numsegments)::bigint else sum(idx_scan) end idx_scan, + max(last_idx_scan) as last_idx_scan, + case when d.policytype = 'r' then (sum(idx_tup_fetch)/d.numsegments)::bigint else sum(idx_tup_fetch) end idx_tup_fetch, + case when d.policytype = 'r' then (sum(n_tup_ins)/d.numsegments)::bigint else sum(n_tup_ins) end n_tup_ins, + case when d.policytype = 'r' then (sum(n_tup_upd)/d.numsegments)::bigint else sum(n_tup_upd) end n_tup_upd, + case when d.policytype = 'r' then (sum(n_tup_del)/d.numsegments)::bigint else sum(n_tup_del) end n_tup_del, + case when d.policytype = 'r' then (sum(n_tup_hot_upd)/d.numsegments)::bigint else sum(n_tup_hot_upd) end n_tup_hot_upd, + case when d.policytype = 'r' then (sum(n_tup_newpage_upd)/d.numsegments)::bigint else sum(n_tup_newpage_upd) end n_tup_newpage_upd, + case when d.policytype = 'r' then (sum(n_live_tup)/d.numsegments)::bigint else sum(n_live_tup) end n_live_tup, + case when d.policytype = 'r' then (sum(n_dead_tup)/d.numsegments)::bigint else sum(n_dead_tup) end n_dead_tup, + case when d.policytype = 'r' then (sum(n_mod_since_analyze)/d.numsegments)::bigint else sum(n_mod_since_analyze) end n_mod_since_analyze, + case when d.policytype = 'r' then (sum(n_ins_since_vacuum)/d.numsegments)::bigint else sum(n_ins_since_vacuum) end n_ins_since_vacuum, + max(last_vacuum) as last_vacuum, + max(last_autovacuum) as last_autovacuum, + max(last_analyze) as last_analyze, + max(last_autoanalyze) as last_autoanalyze, + max(vacuum_count) as vacuum_count, + max(autovacuum_count) as autovacuum_count, + max(analyze_count) as analyze_count, + max(autoanalyze_count) as autoanalyze_count + FROM + gp_dist_random('pg_stat_all_tables') allt + inner join pg_class c + on allt.relid = c.oid + left outer join gp_distribution_policy d + on allt.relid = d.localoid + WHERE + relid >= 16384 + and ( + d.localoid is not null + or c.relkind in ('o', 'b', 'M') + ) + GROUP BY allt.relid, allt.schemaname, allt.relname, d.policytype, d.numsegments + + UNION ALL + + SELECT + * + FROM + pg_stat_all_tables + WHERE + relid < 16384) m, pg_stat_all_tables s +WHERE m.relid = s.relid; + +CREATE VIEW gp_stat_user_tables_summary AS + SELECT * FROM gp_stat_all_tables_summary + WHERE schemaname NOT IN ('pg_catalog', 'information_schema', 'pg_aoseg') AND + schemaname !~ '^pg_toast'; + +CREATE VIEW gp_stat_sys_tables_summary AS + SELECT * FROM gp_stat_all_tables_summary + WHERE schemaname IN ('pg_catalog', 'information_schema', 'pg_aoseg') OR + schemaname ~ '^pg_toast'; + +CREATE VIEW gp_stat_xact_all_tables_summary AS +SELECT + sxa.relid, + sxa.schemaname, + sxa.relname, + CASE WHEN dst.policytype = 'r' THEN (sum(sxa.seq_scan)/dst.numsegments)::bigint ELSE sum(sxa.seq_scan) END AS seq_scan, + CASE WHEN dst.policytype = 'r' THEN (sum(sxa.seq_tup_read)/dst.numsegments)::bigint ELSE sum(sxa.seq_tup_read) END AS seq_tup_read, + CASE WHEN dst.policytype = 'r' THEN (sum(sxa.idx_scan)/dst.numsegments)::bigint ELSE sum(sxa.idx_scan) END AS idx_scan, + CASE WHEN dst.policytype = 'r' THEN (sum(sxa.idx_tup_fetch)/dst.numsegments)::bigint ELSE sum(sxa.idx_tup_fetch) END AS idx_tup_fetch, + CASE WHEN dst.policytype = 'r' THEN (sum(sxa.n_tup_ins)/dst.numsegments)::bigint ELSE sum(sxa.n_tup_ins) END AS n_tup_ins, + CASE WHEN dst.policytype = 'r' THEN (sum(sxa.n_tup_upd)/dst.numsegments)::bigint ELSE sum(sxa.n_tup_upd) END AS n_tup_upd, + CASE WHEN dst.policytype = 'r' THEN (sum(sxa.n_tup_del)/dst.numsegments)::bigint ELSE sum(sxa.n_tup_del) END AS n_tup_del, + CASE WHEN dst.policytype = 'r' THEN (sum(sxa.n_tup_hot_upd)/dst.numsegments)::bigint ELSE sum(sxa.n_tup_hot_upd) END AS n_tup_hot_upd, + CASE WHEN dst.policytype = 'r' THEN (sum(sxa.n_tup_newpage_upd)/dst.numsegments)::bigint ELSE sum(sxa.n_tup_newpage_upd) END AS n_tup_newpage_upd +FROM + gp_stat_xact_all_tables sxa + LEFT OUTER JOIN gp_distribution_policy dst + ON sxa.relid = dst.localoid +GROUP BY + sxa.relid, + sxa.schemaname, + sxa.relname, + dst.policytype, + dst.numsegments; + +CREATE VIEW gp_stat_xact_sys_tables_summary as + SELECT * FROM gp_stat_xact_all_tables_summary + WHERE schemaname IN ('pg_catalog', 'information_schema', 'pg_aoseg') OR + schemaname ~ '^pg_toast'; + +CREATE VIEW gp_stat_xact_user_tables_summary AS + SELECT * FROM gp_stat_xact_all_tables_summary + WHERE schemaname NOT IN ('pg_catalog', 'information_schema', 'pg_aoseg') AND + schemaname !~ '^pg_toast'; + +-- Gather data from segments on user tables, and use data on coordinator on system tables. +CREATE VIEW gp_stat_all_indexes_summary AS +SELECT + s.relid, + s.indexrelid, + s.schemaname, + s.relname, + s.indexrelname, + m.idx_scan, + m.last_idx_scan, + m.idx_tup_read, + m.idx_tup_fetch +FROM + (SELECT + alli.relid, + alli.indexrelid, + alli.schemaname, + alli.relname, + alli.indexrelname, + case when d.policytype = 'r' then (sum(alli.idx_scan)/d.numsegments)::bigint else sum(alli.idx_scan) end idx_scan, + max(last_idx_scan) as last_idx_scan, + case when d.policytype = 'r' then (sum(alli.idx_tup_read)/d.numsegments)::bigint else sum(alli.idx_tup_read) end idx_tup_read, + case when d.policytype = 'r' then (sum(alli.idx_tup_fetch)/d.numsegments)::bigint else sum(alli.idx_tup_fetch) end idx_tup_fetch + FROM + gp_dist_random('pg_stat_all_indexes') alli + inner join pg_class c + on alli.relid = c.oid + left outer join gp_distribution_policy d + on alli.relid = d.localoid + WHERE + relid >= 16384 + GROUP BY alli.relid, alli.indexrelid, alli.schemaname, alli.relname, alli.indexrelname, d.policytype, d.numsegments + + UNION ALL + + SELECT + * + FROM + pg_stat_all_indexes + WHERE + relid < 16384) m, pg_stat_all_indexes s +WHERE m.relid = s.relid; + +CREATE VIEW gp_stat_sys_indexes_summary AS + SELECT * FROM gp_stat_all_indexes_summary + WHERE schemaname IN ('pg_catalog', 'information_schema', 'pg_aoseg') OR + schemaname ~ '^pg_toast'; + +CREATE VIEW gp_stat_user_indexes_summary AS + SELECT * FROM gp_stat_all_indexes_summary + WHERE schemaname NOT IN ('pg_catalog', 'information_schema', 'pg_aoseg') AND + schemaname !~ '^pg_toast'; + +CREATE VIEW gp_statio_all_tables_summary as +SELECT + sat.relid, + sat.schemaname, + sat.relname, + CASE WHEN dst.policytype = 'r' THEN (sum(sat.heap_blks_read)/dst.numsegments)::bigint ELSE sum(sat.heap_blks_read) END AS heap_blks_read, + CASE WHEN dst.policytype = 'r' THEN (sum(sat.heap_blks_hit)/dst.numsegments)::bigint ELSE sum(sat.heap_blks_hit) END AS heap_blks_hit, + CASE WHEN dst.policytype = 'r' THEN (sum(sat.idx_blks_read)/dst.numsegments)::bigint ELSE sum(sat.idx_blks_read) END AS idx_blks_read, + CASE WHEN dst.policytype = 'r' THEN (sum(sat.idx_blks_hit)/dst.numsegments)::bigint ELSE sum(sat.idx_blks_hit) END AS idx_blks_hit, + CASE WHEN dst.policytype = 'r' THEN (sum(sat.toast_blks_read)/dst.numsegments)::bigint ELSE sum(sat.toast_blks_read) END AS toast_blks_read, + CASE WHEN dst.policytype = 'r' THEN (sum(sat.toast_blks_hit)/dst.numsegments)::bigint ELSE sum(sat.toast_blks_hit) END AS toast_blks_hit, + CASE WHEN dst.policytype = 'r' THEN (sum(sat.tidx_blks_read)/dst.numsegments)::bigint ELSE sum(sat.tidx_blks_read) END AS tidx_blks_read, + CASE WHEN dst.policytype = 'r' THEN (sum(sat.tidx_blks_hit)/dst.numsegments)::bigint ELSE sum(sat.tidx_blks_hit) END AS tidx_blks_hit +FROM + gp_statio_all_tables sat + LEFT OUTER JOIN gp_distribution_policy dst + ON sat.relid = dst.localoid +GROUP BY + sat.relid, + sat.schemaname, + sat.relname, + dst.policytype, + dst.numsegments; + +CREATE VIEW gp_statio_sys_tables_summary AS + SELECT * FROM gp_statio_all_tables_summary + WHERE schemaname IN ('pg_catalog', 'information_schema', 'pg_aoseg') OR + schemaname ~ '^pg_toast'; + +CREATE VIEW gp_statio_user_tables_summary AS + SELECT * FROM gp_stat_all_tables_summary + WHERE schemaname NOT IN ('pg_catalog', 'information_schema', 'pg_aoseg') AND + schemaname !~ '^pg_toast'; + +CREATE VIEW gp_statio_all_sequences_summary as +SELECT + sas.relid, + sas.schemaname, + sas.relname, + CASE WHEN dst.policytype = 'r' THEN (sum(sas.blks_read)/dst.numsegments)::bigint ELSE sum(sas.blks_read) END AS blks_read, + CASE WHEN dst.policytype = 'r' THEN (sum(sas.blks_hit)/dst.numsegments)::bigint ELSE sum(sas.blks_hit) END AS blks_hit +FROM + gp_statio_all_sequences sas + LEFT OUTER JOIN gp_distribution_policy dst + ON sas.relid = dst.localoid +GROUP BY + sas.relid, + sas.schemaname, + sas.relname, + dst.policytype, + dst.numsegments; + +CREATE VIEW gp_statio_sys_sequences_summary AS + SELECT * FROM gp_statio_all_sequences_summary + WHERE schemaname IN ('pg_catalog', 'information_schema', 'pg_aoseg') OR + schemaname ~ '^pg_toast'; + +CREATE VIEW gp_statio_user_sequences_summary AS + SELECT * FROM gp_statio_all_sequences_summary + WHERE schemaname NOT IN ('pg_catalog', 'information_schema', 'pg_aoseg') AND + schemaname !~ '^pg_toast'; + +CREATE VIEW gp_statio_all_indexes_summary AS +SELECT + sai.relid, + sai.indexrelid, + sai.schemaname, + sai.relname, + sai.indexrelname, + CASE WHEN dst.policytype = 'r' THEN (sum(sai.idx_blks_read)/dst.numsegments)::bigint ELSE sum(sai.idx_blks_read) END AS idx_blks_read, + CASE WHEN dst.policytype = 'r' THEN (sum(sai.idx_blks_hit)/dst.numsegments)::bigint ELSE sum(sai.idx_blks_hit) END AS idx_blks_hit +FROM + gp_statio_all_indexes sai + LEFT OUTER JOIN gp_distribution_policy dst + ON sai.relid = dst.localoid +GROUP BY + sai.relid, + sai.indexrelid, + sai.schemaname, + sai.relname, + sai.indexrelname, + dst.policytype, + dst.numsegments; + +CREATE VIEW gp_statio_sys_indexes_summary AS + SELECT * FROM gp_statio_all_indexes_summary + WHERE schemaname IN ('pg_catalog', 'information_schema', 'pg_aoseg') OR + schemaname ~ '^pg_toast'; + +CREATE VIEW gp_statio_user_indexes_summary AS + SELECT * FROM gp_statio_all_indexes_summary + WHERE schemaname NOT IN ('pg_catalog', 'information_schema', 'pg_aoseg') AND + schemaname !~ '^pg_toast'; + +CREATE VIEW gp_stat_user_functions_summary AS +SELECT + guf.funcid, + guf.schemaname, + guf.funcname, + sum(guf.calls) AS calls, + sum(guf.total_time) AS total_time, + sum(guf.self_time) AS self_time +FROM + gp_stat_user_functions guf +GROUP BY + guf.funcid, + guf.schemaname, + guf.funcname; + +CREATE VIEW gp_stat_xact_user_functions_summary AS +SELECT + xuf.funcid, + xuf.schemaname, + xuf.funcname, + sum(xuf.calls) AS calls, + sum(xuf.total_time) AS total_time, + sum(xuf.self_time) AS self_time +FROM + gp_stat_xact_user_functions xuf +GROUP BY + xuf.funcid, + xuf.schemaname, + xuf.funcname; + +CREATE VIEW gp_stat_slru_summary AS +SELECT + gss.name, + sum(gss.blks_zeroed) AS blks_zeroed, + sum(gss.blks_hit) AS blks_hit, + sum(gss.blks_read) AS blks_read, + sum(gss.blks_written) AS blks_written, + sum(gss.blks_exists) AS blks_exists, + sum(gss.flushes) AS flushes, + sum(gss.truncates) AS truncates, + max(gss.stats_reset) AS stats_reset +FROM + gp_stat_slru gss +GROUP BY + gss.name; + + +CREATE VIEW gp_stat_progress_vacuum_summary AS +SELECT + max(coalesce(a1.pid, 0)) as pid, + a.datid, + a.datname, + a.relid, + a.phase, + case when d.policytype = 'r' then (sum(a.heap_blks_total)/d.numsegments)::bigint else sum(a.heap_blks_total) end heap_blks_total, + case when d.policytype = 'r' then (sum(a.heap_blks_scanned)/d.numsegments)::bigint else sum(a.heap_blks_scanned) end heap_blks_scanned, + case when d.policytype = 'r' then (sum(a.heap_blks_vacuumed)/d.numsegments)::bigint else sum(a.heap_blks_vacuumed) end heap_blks_vacuumed, + case when d.policytype = 'r' then (sum(a.index_vacuum_count)/d.numsegments)::bigint else sum(a.index_vacuum_count) end index_vacuum_count, + case when d.policytype = 'r' then (sum(a.max_dead_tuples)/d.numsegments)::bigint else sum(a.max_dead_tuples) end max_dead_tuples, + case when d.policytype = 'r' then (sum(a.num_dead_tuples)/d.numsegments)::bigint else sum(a.num_dead_tuples) end num_dead_tuples +FROM gp_stat_progress_vacuum a + JOIN pg_class c ON a.relid = c.oid + LEFT JOIN gp_distribution_policy d ON c.oid = d.localoid + LEFT JOIN gp_stat_progress_vacuum a1 ON a.pid = a1.pid AND a1.gp_segment_id = -1 +WHERE a.gp_segment_id > -1 +GROUP BY a.datid, a.datname, a.relid, a.phase, d.policytype, d.numsegments; + +CREATE OR REPLACE VIEW gp_stat_progress_analyze_summary AS +SELECT + max(coalesce(a1.pid, 0)) as pid, + a.datid, + a.datname, + a.relid, + a.phase, + case when d.policytype = 'r' then (sum(a.sample_blks_total)/d.numsegments)::bigint else sum(a.sample_blks_total) end sample_blks_total, + case when d.policytype = 'r' then (sum(a.sample_blks_scanned)/d.numsegments)::bigint else sum(a.sample_blks_scanned) end sample_blks_scanned, + case when d.policytype = 'r' then (sum(a.ext_stats_total)/d.numsegments)::bigint else sum(a.ext_stats_total) end ext_stats_total, + case when d.policytype = 'r' then (sum(a.ext_stats_computed)/d.numsegments)::bigint else sum(a.ext_stats_computed) end ext_stats_computed, + case when d.policytype = 'r' then (sum(a.child_tables_total)/d.numsegments)::bigint else sum(a.child_tables_total) end child_tables_total, + case when d.policytype = 'r' then (sum(a.child_tables_done)/d.numsegments)::bigint else sum(a.child_tables_done) end child_tables_done +FROM gp_stat_progress_analyze a + JOIN pg_class c ON a.relid = c.oid + LEFT JOIN gp_distribution_policy d ON c.oid = d.localoid + LEFT JOIN gp_stat_progress_analyze a1 ON a.pid = a1.pid AND a1.gp_segment_id = -1 +WHERE a.gp_segment_id > -1 +GROUP BY a.datid, a.datname, a.relid, a.phase, d.policytype, d.numsegments; + +CREATE OR REPLACE VIEW gp_stat_progress_cluster_summary AS +SELECT + max(coalesce(a1.pid, 0)) as pid, + a.datid, + a.datname, + a.relid, + a.command, + a.phase, + a.cluster_index_relid, + case when d.policytype = 'r' then (sum(a.heap_tuples_scanned)/d.numsegments)::bigint else sum(a.heap_tuples_scanned) end heap_tuples_scanned, + case when d.policytype = 'r' then (sum(a.heap_tuples_written)/d.numsegments)::bigint else sum(a.heap_tuples_written) end heap_tuples_written, + case when d.policytype = 'r' then (sum(a.heap_blks_total)/d.numsegments)::bigint else sum(a.heap_blks_total) end heap_blks_total, + case when d.policytype = 'r' then (sum(a.heap_blks_scanned)/d.numsegments)::bigint else sum(a.heap_blks_scanned) end heap_blks_scanned, + case when d.policytype = 'r' then (sum(a.index_rebuild_count)/d.numsegments)::bigint else sum(a.index_rebuild_count) end index_rebuild_count +FROM gp_stat_progress_cluster a + JOIN pg_class c ON a.relid = c.oid + LEFT JOIN gp_distribution_policy d ON c.oid = d.localoid + LEFT JOIN gp_stat_progress_cluster a1 ON a.pid = a1.pid AND a1.gp_segment_id = -1 +WHERE a.gp_segment_id > -1 +GROUP BY a.datid, a.datname, a.relid, a.command, a.phase, a.cluster_index_relid, d.policytype, d.numsegments; + +CREATE OR REPLACE VIEW gp_stat_progress_create_index_summary AS +SELECT + max(coalesce(a1.pid, 0)) as pid, + a.datid, + a.datname, + a.relid, + a.index_relid, + a.command, + a.phase, + case when d.policytype = 'r' then (sum(a.lockers_total)/d.numsegments)::bigint else sum(a.lockers_total) end lockers_total, + case when d.policytype = 'r' then (sum(a.lockers_done)/d.numsegments)::bigint else sum(a.lockers_done) end lockers_done, + max(a.current_locker_pid) as current_locker_pid, + case when d.policytype = 'r' then (sum(a.blocks_total)/d.numsegments)::bigint else sum(a.blocks_total) end blocks_total, + case when d.policytype = 'r' then (sum(a.blocks_done)/d.numsegments)::bigint else sum(a.blocks_done) end blocks_done, + case when d.policytype = 'r' then (sum(a.tuples_total)/d.numsegments)::bigint else sum(a.tuples_total) end tuples_total, + case when d.policytype = 'r' then (sum(a.tuples_done)/d.numsegments)::bigint else sum(a.tuples_done) end tuples_done, + case when d.policytype = 'r' then (sum(a.partitions_total)/d.numsegments)::bigint else sum(a.partitions_total) end partitions_total, + case when d.policytype = 'r' then (sum(a.partitions_done)/d.numsegments)::bigint else sum(a.partitions_done) end partitions_done +FROM gp_stat_progress_create_index a + JOIN pg_class c ON a.relid = c.oid + LEFT JOIN gp_distribution_policy d ON c.oid = d.localoid + LEFT JOIN gp_stat_progress_create_index a1 ON a.pid = a1.pid AND a1.gp_segment_id = -1 +WHERE a.gp_segment_id > -1 +GROUP BY a.datid, a.datname, a.relid, a.index_relid, a.command, a.phase, d.policytype, d.numsegments; + +CREATE OR REPLACE VIEW gp_stat_io_summary AS +SELECT + backend_type, + object, + context, + sum(reads) as reads, + sum(read_time) as read_time, + sum(writes) as writes, + sum(write_time) as write_time, + sum(writebacks) as writebacks, + sum(writeback_time) as writeback_time, + sum(extends) as extends, + sum(extend_time) as extend_time, + sum(op_bytes) as op_bytes, + sum(hits) as hits, + sum(evictions) as evictions, + sum(reuses) as reuses, + sum(fsyncs) as fsyncs, + sum(fsync_time) as fsync_time, + max(stats_reset) as stats_reset +FROM gp_stat_io +GROUP BY backend_type, object, context; diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c index f2fff2c8607..5f7b8faf8e1 100644 --- a/src/backend/commands/analyze.c +++ b/src/backend/commands/analyze.c @@ -1875,6 +1875,7 @@ acquire_sample_rows(Relation onerel, int elevel, pgstat_progress_update_param(PROGRESS_ANALYZE_BLOCKS_DONE, ++blksdone); + SIMPLE_FAULT_INJECTOR("analyze_block"); } ExecDropSingleTupleTableSlot(slot); diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 244561532e2..80585a878a7 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -217,6 +217,7 @@ ExecVacuum(ParseState *pstate, VacuumStmt *vacstmt, bool isTopLevel, bool auto_s /* By default parallel vacuum is enabled */ params.nworkers = 0; + params.buffer_usage_limit = 0; /* * Set this to an invalid value so it is clear whether or not a @@ -262,6 +263,7 @@ ExecVacuum(ParseState *pstate, VacuumStmt *vacstmt, bool isTopLevel, bool auto_s } ring_size = result; + params.buffer_usage_limit = result; } else if (!vacstmt->is_vacuumcmd) ereport(ERROR, @@ -370,7 +372,9 @@ ExecVacuum(ParseState *pstate, VacuumStmt *vacstmt, bool isTopLevel, bool auto_s (process_toast ? VACOPT_PROCESS_TOAST : 0) | (skip_database_stats ? VACOPT_SKIP_DATABASE_STATS : 0) | (only_database_stats ? VACOPT_ONLY_DATABASE_STATS : 0) | - (update_datfrozenxid ? VACOPT_UPDATE_DATFROZENXID : 0); + (update_datfrozenxid ? VACOPT_UPDATE_DATFROZENXID : 0) | + (params.nworkers != 0 ? VACOPT_PARALLEL : 0) | + (params.buffer_usage_limit != 0 ? VACOPT_BUFFER_USAGE_LIMIT : 0) ; if (rootonly) params.options |= VACOPT_ROOTONLY; @@ -3439,6 +3443,18 @@ vacuum_params_to_options_list(VacuumParams *params) options = lappend(options, makeDefElem("only_database_stats", (Node *) makeInteger(1), -1)); optmask &= ~VACOPT_ONLY_DATABASE_STATS; } + if ((optmask & VACOPT_PARALLEL)) + { + Assert(params->nworkers!=0); + options = lappend(options, makeDefElem("parallel", (Node *) makeInteger(params->nworkers==-1 ? 0 : params->nworkers), -1)); + optmask &= ~VACOPT_PARALLEL; + } + if ((optmask & VACOPT_BUFFER_USAGE_LIMIT)) + { + Assert(params->buffer_usage_limit!=0); + options = lappend(options, makeDefElem("buffer_usage_limit", (Node *) makeInteger(params->buffer_usage_limit), -1)); + optmask &= ~VACOPT_BUFFER_USAGE_LIMIT; + } if (optmask & VACUUM_AO_PHASE_MASK) diff --git a/src/backend/commands/vacuum_ao.c b/src/backend/commands/vacuum_ao.c index 3a2dc7e6627..dd0522f1986 100644 --- a/src/backend/commands/vacuum_ao.c +++ b/src/backend/commands/vacuum_ao.c @@ -634,6 +634,7 @@ vacuum_appendonly_index(Relation indexRelation, pg_rusage_init(&ru0); ivinfo.index = indexRelation; + ivinfo.heaprel = aoRelation; ivinfo.analyze_only = false; ivinfo.message_level = elevel; /* @@ -808,6 +809,7 @@ scan_index(Relation indrel, Relation aorel, int elevel, BufferAccessStrategy vac pg_rusage_init(&ru0); ivinfo.index = indrel; + ivinfo.heaprel = aorel; ivinfo.analyze_only = false; ivinfo.message_level = elevel; /* diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c deleted file mode 100644 index 309a101fe02..00000000000 --- a/src/backend/postmaster/pgstat.c +++ /dev/null @@ -1,6442 +0,0 @@ -/* ---------- - * pgstat.c - * - * All the statistics collector stuff hacked up in one big, ugly file. - * - * TODO: - Separate collector, postmaster and backend stuff - * into different files. - * - * - Add some automatic call for pgstat vacuuming. - * - * - Add a pgstat config column to pg_database, so this - * entire thing can be enabled/disabled on a per db basis. - * - * Copyright (c) 2001-2021, PostgreSQL Global Development Group - * - * src/backend/postmaster/pgstat.c - * ---------- - */ -#include "postgres.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef HAVE_SYS_SELECT_H -#include -#endif - -#include "access/heapam.h" -#include "access/htup_details.h" -#include "access/tableam.h" -#include "access/transam.h" -#include "access/twophase_rmgr.h" -#include "access/xact.h" -#include "access/xlog.h" -#include "catalog/pg_database.h" -#include "catalog/pg_proc.h" -#include "executor/instrument.h" -#include "common/hashfn.h" -#include "common/ip.h" -#include "executor/instrument.h" -#include "libpq/libpq.h" -#include "libpq/pqsignal.h" -#include "mb/pg_wchar.h" -#include "miscadmin.h" -#include "pgstat.h" -#include "postmaster/autovacuum.h" -#include "postmaster/fork_process.h" -#include "postmaster/interrupt.h" -#include "postmaster/postmaster.h" -#include "replication/slot.h" -#include "replication/walsender.h" -#include "storage/backendid.h" -#include "storage/dsm.h" -#include "storage/fd.h" -#include "storage/ipc.h" -#include "storage/latch.h" -#include "storage/lmgr.h" -#include "storage/pg_shmem.h" -#include "storage/proc.h" -#include "storage/procsignal.h" -#include "utils/builtins.h" -#include "utils/guc.h" -#include "utils/memutils.h" -#include "utils/ps_status.h" -#include "utils/rel.h" -#include "utils/snapmgr.h" -#include "utils/timestamp.h" - -#include "libpq-int.h" -#include "cdb/cdbconn.h" -#include "cdb/cdbdispatchresult.h" -#include "cdb/cdbvars.h" -#include "commands/resgroupcmds.h" -#include "libpq/pqformat.h" -#include "utils/faultinjector.h" -#include "utils/lsyscache.h" - - -/* ---------- - * Timer definitions. - * ---------- - */ -#define PGSTAT_STAT_INTERVAL 500 /* Minimum time between stats file - * updates; in milliseconds. */ - -#define PGSTAT_RETRY_DELAY 10 /* How long to wait between checks for a - * new file; in milliseconds. */ - -#define PGSTAT_MAX_WAIT_TIME 10000 /* Maximum time to wait for a stats - * file update; in milliseconds. */ - -#define PGSTAT_INQ_INTERVAL 640 /* How often to ping the collector for a - * new file; in milliseconds. */ - -#define PGSTAT_RESTART_INTERVAL 60 /* How often to attempt to restart a - * failed statistics collector; in - * seconds. */ - -#define PGSTAT_POLL_LOOP_COUNT (PGSTAT_MAX_WAIT_TIME / PGSTAT_RETRY_DELAY) -#define PGSTAT_INQ_LOOP_COUNT (PGSTAT_INQ_INTERVAL / PGSTAT_RETRY_DELAY) - -/* Minimum receive buffer size for the collector's socket. */ -#define PGSTAT_MIN_RCVBUF (100 * 1024) - - -/* ---------- - * The initial size hints for the hash tables used in the collector. - * ---------- - */ -#define PGSTAT_DB_HASH_SIZE 16 -#define PGSTAT_TAB_HASH_SIZE 512 -#define PGSTAT_QUEUE_HASH_SIZE 8 -#define PGSTAT_FUNCTION_HASH_SIZE 512 -#define PGSTAT_REPLSLOT_HASH_SIZE 32 - - -/* ---------- - * GUC parameters - * ---------- - */ -bool pgstat_track_counts = false; -int pgstat_track_functions = TRACK_FUNC_OFF; - -bool pgstat_collect_queuelevel = false; - -/* ---------- - * Built from GUC parameter - * ---------- - */ -char *pgstat_stat_directory = NULL; -char *pgstat_stat_filename = NULL; -char *pgstat_stat_tmpname = NULL; - -/* - * BgWriter and WAL global statistics counters. - * Stored directly in a stats message structure so they can be sent - * without needing to copy things around. We assume these init to zeroes. - */ -PgStat_MsgBgWriter BgWriterStats; -PgStat_MsgWal WalStats; - -/* - * WAL usage counters saved from pgWALUsage at the previous call to - * pgstat_send_wal(). This is used to calculate how much WAL usage - * happens between pgstat_send_wal() calls, by substracting - * the previous counters from the current ones. - */ -static WalUsage prevWalUsage; - -/* - * List of SLRU names that we keep stats for. There is no central registry of - * SLRUs, so we use this fixed list instead. The "other" entry is used for - * all SLRUs without an explicit entry (e.g. SLRUs in extensions). - */ -static const char *const slru_names[] = { - "CommitTs", - "MultiXactMember", - "MultiXactOffset", - "Notify", - "Serial", - "Subtrans", - "Xact", - "other" /* has to be last */ -}; - -#define SLRU_NUM_ELEMENTS lengthof(slru_names) - -/* - * SLRU statistics counts waiting to be sent to the collector. These are - * stored directly in stats message format so they can be sent without needing - * to copy things around. We assume this variable inits to zeroes. Entries - * are one-to-one with slru_names[]. - */ -static PgStat_MsgSLRU SLRUStats[SLRU_NUM_ELEMENTS]; - -/* ---------- - * Local data - * ---------- - */ -NON_EXEC_STATIC pgsocket pgStatSock = PGINVALID_SOCKET; - -static struct sockaddr_storage pgStatAddr; - -static time_t last_pgstat_start_time; - -static bool pgStatRunningInCollector = false; - -/* - * Structures in which backends store per-table info that's waiting to be - * sent to the collector. - * - * NOTE: once allocated, TabStatusArray structures are never moved or deleted - * for the life of the backend. Also, we zero out the t_id fields of the - * contained PgStat_TableStatus structs whenever they are not actively in use. - * This allows relcache pgstat_info pointers to be treated as long-lived data, - * avoiding repeated searches in pgstat_initstats() when a relation is - * repeatedly opened during a transaction. - */ -#define TABSTAT_QUANTUM 100 /* we alloc this many at a time */ - -typedef struct TabStatusArray -{ - struct TabStatusArray *tsa_next; /* link to next array, if any */ - int tsa_used; /* # entries currently used */ - PgStat_TableStatus tsa_entries[TABSTAT_QUANTUM]; /* per-table data */ -} TabStatusArray; - -static TabStatusArray *pgStatTabList = NULL; - -/* - * pgStatTabHash entry: map from relation OID to PgStat_TableStatus pointer - */ -typedef struct TabStatHashEntry -{ - Oid t_id; - PgStat_TableStatus *tsa_entry; -} TabStatHashEntry; - -/* - * Hash table for O(1) t_id -> tsa_entry lookup - */ -static HTAB *pgStatTabHash = NULL; - -/* - * Backends store per-function info that's waiting to be sent to the collector - * in this hash table (indexed by function OID). - */ -static HTAB *pgStatFunctions = NULL; - -/* - * Indicates if backend has some function stats that it hasn't yet - * sent to the collector. - */ -static bool have_function_stats = false; - -/* - * Tuple insertion/deletion counts for an open transaction can't be propagated - * into PgStat_TableStatus counters until we know if it is going to commit - * or abort. Hence, we keep these counts in per-subxact structs that live - * in TopTransactionContext. This data structure is designed on the assumption - * that subxacts won't usually modify very many tables. - */ -typedef struct PgStat_SubXactStatus -{ - int nest_level; /* subtransaction nest level */ - struct PgStat_SubXactStatus *prev; /* higher-level subxact if any */ - PgStat_TableXactStatus *first; /* head of list for this subxact */ -} PgStat_SubXactStatus; - -static PgStat_SubXactStatus *pgStatXactStack = NULL; - -static int pgStatXactCommit = 0; -static int pgStatXactRollback = 0; -PgStat_Counter pgStatBlockReadTime = 0; -PgStat_Counter pgStatBlockWriteTime = 0; -static PgStat_Counter pgLastSessionReportTime = 0; -PgStat_Counter pgStatActiveTime = 0; -PgStat_Counter pgStatTransactionIdleTime = 0; -SessionEndType pgStatSessionEndCause = DISCONNECT_NORMAL; - -/* Record that's written to 2PC state file when pgstat state is persisted */ -typedef struct TwoPhasePgStatRecord -{ - PgStat_Counter tuples_inserted; /* tuples inserted in xact */ - PgStat_Counter tuples_updated; /* tuples updated in xact */ - PgStat_Counter tuples_deleted; /* tuples deleted in xact */ - PgStat_Counter inserted_pre_trunc; /* tuples inserted prior to truncate */ - PgStat_Counter updated_pre_trunc; /* tuples updated prior to truncate */ - PgStat_Counter deleted_pre_trunc; /* tuples deleted prior to truncate */ - Oid t_id; /* table's OID */ - bool t_shared; /* is it a shared catalog? */ - bool t_truncated; /* was the relation truncated? */ -} TwoPhasePgStatRecord; - -typedef struct PgStatTabRecordFromQE -{ - TwoPhasePgStatRecord table_stat; - int nest_level; -} PgStatTabRecordFromQE; - -/* - * Info about current "snapshot" of stats file - */ -static MemoryContext pgStatLocalContext = NULL; -static HTAB *pgStatDBHash = NULL; - -static HTAB *pgStatQueueHash = NULL; /* GPDB */ -static HTAB *localStatPortalHash = NULL; /* GPDB. per backend portal queue stats.*/ - -/* - * Cluster wide statistics, kept in the stats collector. - * Contains statistics that are not collected per database - * or per table. - */ -static PgStat_ArchiverStats archiverStats; -static PgStat_GlobalStats globalStats; -static PgStat_WalStats walStats; -static PgStat_SLRUStats slruStats[SLRU_NUM_ELEMENTS]; -static HTAB *replSlotStatHash = NULL; - -/* - * List of OIDs of databases we need to write out. If an entry is InvalidOid, - * it means to write only the shared-catalog stats ("DB 0"); otherwise, we - * will write both that DB's data and the shared stats. - */ -static List *pending_write_requests = NIL; - -/* - * Total time charged to functions so far in the current backend. - * We use this to help separate "self" and "other" time charges. - * (We assume this initializes to zero.) - */ -static instr_time total_func_time; - - -/* ---------- - * Local function forward declarations - * ---------- - */ -#ifdef EXEC_BACKEND -static pid_t pgstat_forkexec(void); -#endif - -NON_EXEC_STATIC void PgstatCollectorMain(int argc, char *argv[]) pg_attribute_noreturn(); - -static PgStat_StatDBEntry *pgstat_get_db_entry(Oid databaseid, bool create); -static PgStat_StatTabEntry *pgstat_get_tab_entry(PgStat_StatDBEntry *dbentry, - Oid tableoid, bool create); -static PgStat_StatQueueEntry *pgstat_get_queue_entry(Oid queueid, bool create); /*GPDB*/ - -static void pgstat_write_statsfiles(bool permanent, bool allDbs); -static void pgstat_write_db_statsfile(PgStat_StatDBEntry *dbentry, bool permanent); -static HTAB *pgstat_read_statsfiles(Oid onlydb, bool permanent, bool deep); -static void pgstat_read_db_statsfile(Oid databaseid, HTAB *tabhash, HTAB *funchash, bool permanent); -static void backend_read_statsfile(void); - -static bool pgstat_write_statsfile_needed(void); -static bool pgstat_db_requested(Oid databaseid); - -static PgStat_StatReplSlotEntry *pgstat_get_replslot_entry(NameData name, bool create_it); -static void pgstat_reset_replslot(PgStat_StatReplSlotEntry *slotstats, TimestampTz ts); - -static void pgstat_send_tabstat(PgStat_MsgTabstat *tsmsg, TimestampTz now); -static void pgstat_send_funcstats(void); -static void pgstat_send_slru(void); -static HTAB *pgstat_collect_oids(Oid catalogid, AttrNumber anum_oid); -static bool pgstat_should_report_connstat(void); -static void pgstat_report_disconnect(Oid dboid); - -static PgStat_TableStatus *get_tabstat_entry(Oid rel_id, bool isshared); - -static void pgstat_setup_memcxt(void); - -static void pgstat_setheader(PgStat_MsgHdr *hdr, StatMsgType mtype); -static void pgstat_send(void *msg, int len); - -static void pgstat_recv_inquiry(PgStat_MsgInquiry *msg, int len); -static void pgstat_recv_tabstat(PgStat_MsgTabstat *msg, int len); -static void pgstat_recv_tabpurge(PgStat_MsgTabpurge *msg, int len); -static void pgstat_recv_dropdb(PgStat_MsgDropdb *msg, int len); -static void pgstat_recv_resetcounter(PgStat_MsgResetcounter *msg, int len); -static void pgstat_recv_resetsharedcounter(PgStat_MsgResetsharedcounter *msg, int len); -static void pgstat_recv_resetsinglecounter(PgStat_MsgResetsinglecounter *msg, int len); -static void pgstat_recv_resetslrucounter(PgStat_MsgResetslrucounter *msg, int len); -static void pgstat_recv_resetreplslotcounter(PgStat_MsgResetreplslotcounter *msg, int len); -static void pgstat_recv_autovac(PgStat_MsgAutovacStart *msg, int len); -static void pgstat_recv_vacuum(PgStat_MsgVacuum *msg, int len); -static void pgstat_recv_analyze(PgStat_MsgAnalyze *msg, int len); -static void pgstat_recv_archiver(PgStat_MsgArchiver *msg, int len); -static void pgstat_recv_queuestat(PgStat_MsgQueuestat *msg, int len); /* GPDB */ -static void pgstat_recv_bgwriter(PgStat_MsgBgWriter *msg, int len); -static void pgstat_recv_wal(PgStat_MsgWal *msg, int len); -static void pgstat_recv_slru(PgStat_MsgSLRU *msg, int len); -static void pgstat_recv_funcstat(PgStat_MsgFuncstat *msg, int len); -static void pgstat_recv_funcpurge(PgStat_MsgFuncpurge *msg, int len); -static void pgstat_recv_recoveryconflict(PgStat_MsgRecoveryConflict *msg, int len); -static void pgstat_recv_deadlock(PgStat_MsgDeadlock *msg, int len); -static void pgstat_recv_checksum_failure(PgStat_MsgChecksumFailure *msg, int len); -static void pgstat_recv_connect(PgStat_MsgConnect *msg, int len); -static void pgstat_recv_disconnect(PgStat_MsgDisconnect *msg, int len); -static void pgstat_recv_replslot(PgStat_MsgReplSlot *msg, int len); -static void pgstat_recv_tempfile(PgStat_MsgTempFile *msg, int len); - -/* ------------------------------------------------------------ - * Public functions called from postmaster follow - * ------------------------------------------------------------ - */ - -/* ---------- - * pgstat_init() - - * - * Called from postmaster at startup. Create the resources required - * by the statistics collector process. If unable to do so, do not - * fail --- better to let the postmaster start with stats collection - * disabled. - * ---------- - */ -void -pgstat_init(void) -{ - ACCEPT_TYPE_ARG3 alen; - struct addrinfo *addrs = NULL, - *addr, - hints; - int ret; - fd_set rset; - struct timeval tv; - char test_byte; - int sel_res; - int tries = 0; - -#define TESTBYTEVAL ((char) 199) - - /* - * This static assertion verifies that we didn't mess up the calculations - * involved in selecting maximum payload sizes for our UDP messages. - * Because the only consequence of overrunning PGSTAT_MAX_MSG_SIZE would - * be silent performance loss from fragmentation, it seems worth having a - * compile-time cross-check that we didn't. - */ - StaticAssertStmt(sizeof(PgStat_Msg) <= PGSTAT_MAX_MSG_SIZE, - "maximum stats message size exceeds PGSTAT_MAX_MSG_SIZE"); - - /* - * Create the UDP socket for sending and receiving statistic messages - */ - hints.ai_flags = AI_PASSIVE; - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = SOCK_DGRAM; - hints.ai_protocol = 0; - hints.ai_addrlen = 0; - hints.ai_addr = NULL; - hints.ai_canonname = NULL; - hints.ai_next = NULL; - ret = pg_getaddrinfo_all("localhost", NULL, &hints, &addrs); - if (ret || !addrs) - { - ereport(LOG, - (errmsg("could not resolve \"localhost\": %s", - gai_strerror(ret)))); - goto startup_failed; - } - - /* - * On some platforms, pg_getaddrinfo_all() may return multiple addresses - * only one of which will actually work (eg, both IPv6 and IPv4 addresses - * when kernel will reject IPv6). Worse, the failure may occur at the - * bind() or perhaps even connect() stage. So we must loop through the - * results till we find a working combination. We will generate LOG - * messages, but no error, for bogus combinations. - */ - for (addr = addrs; addr; addr = addr->ai_next) - { -#ifdef HAVE_UNIX_SOCKETS - /* Ignore AF_UNIX sockets, if any are returned. */ - if (addr->ai_family == AF_UNIX) - continue; -#endif - - if (++tries > 1) - ereport(LOG, - (errmsg("trying another address for the statistics collector"))); - - /* - * Create the socket. - */ - if ((pgStatSock = socket(addr->ai_family, SOCK_DGRAM, 0)) == PGINVALID_SOCKET) - { - ereport(LOG, - (errcode_for_socket_access(), - errmsg("could not create socket for statistics collector: %m"))); - continue; - } - - /* - * Bind it to a kernel assigned port on localhost and get the assigned - * port via getsockname(). - */ - if (bind(pgStatSock, addr->ai_addr, addr->ai_addrlen) < 0) - { - ereport(LOG, - (errcode_for_socket_access(), - errmsg("could not bind socket for statistics collector: %m"))); - closesocket(pgStatSock); - pgStatSock = PGINVALID_SOCKET; - continue; - } - - alen = sizeof(pgStatAddr); - if (getsockname(pgStatSock, (struct sockaddr *) &pgStatAddr, &alen) < 0) - { - ereport(LOG, - (errcode_for_socket_access(), - errmsg("could not get address of socket for statistics collector: %m"))); - closesocket(pgStatSock); - pgStatSock = PGINVALID_SOCKET; - continue; - } - - /* - * Connect the socket to its own address. This saves a few cycles by - * not having to respecify the target address on every send. This also - * provides a kernel-level check that only packets from this same - * address will be received. - */ - if (connect(pgStatSock, (struct sockaddr *) &pgStatAddr, alen) < 0) - { - ereport(LOG, - (errcode_for_socket_access(), - errmsg("could not connect socket for statistics collector: %m"))); - closesocket(pgStatSock); - pgStatSock = PGINVALID_SOCKET; - continue; - } - - /* - * Try to send and receive a one-byte test message on the socket. This - * is to catch situations where the socket can be created but will not - * actually pass data (for instance, because kernel packet filtering - * rules prevent it). - */ - test_byte = TESTBYTEVAL; - -retry1: - if (send(pgStatSock, &test_byte, 1, 0) != 1) - { - if (errno == EINTR) - goto retry1; /* if interrupted, just retry */ - ereport(LOG, - (errcode_for_socket_access(), - errmsg("could not send test message on socket for statistics collector: %m"))); - closesocket(pgStatSock); - pgStatSock = PGINVALID_SOCKET; - continue; - } - - /* - * There could possibly be a little delay before the message can be - * received. We arbitrarily allow up to half a second before deciding - * it's broken. - */ - for (;;) /* need a loop to handle EINTR */ - { - FD_ZERO(&rset); - FD_SET(pgStatSock, &rset); - - tv.tv_sec = 0; - tv.tv_usec = 500000; - sel_res = select(pgStatSock + 1, &rset, NULL, NULL, &tv); - if (sel_res >= 0 || errno != EINTR) - break; - } - if (sel_res < 0) - { - ereport(LOG, - (errcode_for_socket_access(), - errmsg("select() failed in statistics collector: %m"))); - closesocket(pgStatSock); - pgStatSock = PGINVALID_SOCKET; - continue; - } - if (sel_res == 0 || !FD_ISSET(pgStatSock, &rset)) - { - /* - * This is the case we actually think is likely, so take pains to - * give a specific message for it. - * - * errno will not be set meaningfully here, so don't use it. - */ - ereport(LOG, - (errcode(ERRCODE_CONNECTION_FAILURE), - errmsg("test message did not get through on socket for statistics collector"))); - closesocket(pgStatSock); - pgStatSock = PGINVALID_SOCKET; - continue; - } - - test_byte++; /* just make sure variable is changed */ - -retry2: - if (recv(pgStatSock, &test_byte, 1, 0) != 1) - { - if (errno == EINTR) - goto retry2; /* if interrupted, just retry */ - ereport(LOG, - (errcode_for_socket_access(), - errmsg("could not receive test message on socket for statistics collector: %m"))); - closesocket(pgStatSock); - pgStatSock = PGINVALID_SOCKET; - continue; - } - - if (test_byte != TESTBYTEVAL) /* strictly paranoia ... */ - { - ereport(LOG, - (errcode(ERRCODE_INTERNAL_ERROR), - errmsg("incorrect test message transmission on socket for statistics collector"))); - closesocket(pgStatSock); - pgStatSock = PGINVALID_SOCKET; - continue; - } - - /* If we get here, we have a working socket */ - break; - } - - /* Did we find a working address? */ - if (!addr || pgStatSock == PGINVALID_SOCKET) - goto startup_failed; - - /* - * Set the socket to non-blocking IO. This ensures that if the collector - * falls behind, statistics messages will be discarded; backends won't - * block waiting to send messages to the collector. - */ - if (!pg_set_noblock(pgStatSock)) - { - ereport(LOG, - (errcode_for_socket_access(), - errmsg("could not set statistics collector socket to nonblocking mode: %m"))); - goto startup_failed; - } - - /* - * Try to ensure that the socket's receive buffer is at least - * PGSTAT_MIN_RCVBUF bytes, so that it won't easily overflow and lose - * data. Use of UDP protocol means that we are willing to lose data under - * heavy load, but we don't want it to happen just because of ridiculously - * small default buffer sizes (such as 8KB on older Windows versions). - */ - { - int old_rcvbuf; - int new_rcvbuf; - ACCEPT_TYPE_ARG3 rcvbufsize = sizeof(old_rcvbuf); - - if (getsockopt(pgStatSock, SOL_SOCKET, SO_RCVBUF, - (char *) &old_rcvbuf, &rcvbufsize) < 0) - { - ereport(LOG, - (errmsg("%s(%s) failed: %m", "getsockopt", "SO_RCVBUF"))); - /* if we can't get existing size, always try to set it */ - old_rcvbuf = 0; - } - - new_rcvbuf = PGSTAT_MIN_RCVBUF; - if (old_rcvbuf < new_rcvbuf) - { - if (setsockopt(pgStatSock, SOL_SOCKET, SO_RCVBUF, - (char *) &new_rcvbuf, sizeof(new_rcvbuf)) < 0) - ereport(LOG, - (errmsg("%s(%s) failed: %m", "setsockopt", "SO_RCVBUF"))); - } - } - - pg_freeaddrinfo_all(hints.ai_family, addrs); - - /* Now that we have a long-lived socket, tell fd.c about it. */ - ReserveExternalFD(); - - return; - -startup_failed: - ereport(LOG, - (errmsg("disabling statistics collector for lack of working socket"))); - - if (addrs) - pg_freeaddrinfo_all(hints.ai_family, addrs); - - if (pgStatSock != PGINVALID_SOCKET) - closesocket(pgStatSock); - pgStatSock = PGINVALID_SOCKET; - - /* - * Adjust GUC variables to suppress useless activity, and for debugging - * purposes (seeing track_counts off is a clue that we failed here). We - * use PGC_S_OVERRIDE because there is no point in trying to turn it back - * on from postgresql.conf without a restart. - */ - SetConfigOption("track_counts", "off", PGC_INTERNAL, PGC_S_OVERRIDE); - pgstat_collect_queuelevel = false; -} - -/* - * subroutine for pgstat_reset_all - */ -static void -pgstat_reset_remove_files(const char *directory) -{ - DIR *dir; - struct dirent *entry; - char fname[MAXPGPATH * 2]; - - dir = AllocateDir(directory); - while ((entry = ReadDir(dir, directory)) != NULL) - { - int nchars; - Oid tmp_oid; - - /* - * Skip directory entries that don't match the file names we write. - * See get_dbstat_filename for the database-specific pattern. - */ - if (strncmp(entry->d_name, "global.", 7) == 0) - nchars = 7; - else - { - nchars = 0; - (void) sscanf(entry->d_name, "db_%u.%n", - &tmp_oid, &nchars); - if (nchars <= 0) - continue; - /* %u allows leading whitespace, so reject that */ - if (strchr("0123456789", entry->d_name[3]) == NULL) - continue; - } - - if (strcmp(entry->d_name + nchars, "tmp") != 0 && - strcmp(entry->d_name + nchars, "stat") != 0) - continue; - - snprintf(fname, sizeof(fname), "%s/%s", directory, - entry->d_name); - unlink(fname); - } - FreeDir(dir); -} - -/* - * pgstat_reset_all() - - * - * Remove the stats files. This is currently used only if WAL - * recovery is needed after a crash. - */ -void -pgstat_reset_all(void) -{ - pgstat_reset_remove_files(pgstat_stat_directory); - pgstat_reset_remove_files(PGSTAT_STAT_PERMANENT_DIRECTORY); -} - -#ifdef EXEC_BACKEND - -/* - * pgstat_forkexec() - - * - * Format up the arglist for, then fork and exec, statistics collector process - */ -static pid_t -pgstat_forkexec(void) -{ - char *av[10]; - int ac = 0; - - av[ac++] = "postgres"; - av[ac++] = "--forkcol"; - av[ac++] = NULL; /* filled in by postmaster_forkexec */ - - av[ac] = NULL; - Assert(ac < lengthof(av)); - - return postmaster_forkexec(ac, av); -} -#endif /* EXEC_BACKEND */ - - -/* - * pgstat_start() - - * - * Called from postmaster at startup or after an existing collector - * died. Attempt to fire up a fresh statistics collector. - * - * Returns PID of child process, or 0 if fail. - * - * Note: if fail, we will be called again from the postmaster main loop. - */ -int -pgstat_start(void) -{ - time_t curtime; - pid_t pgStatPid; - - /* - * Check that the socket is there, else pgstat_init failed and we can do - * nothing useful. - */ - if (pgStatSock == PGINVALID_SOCKET) - return 0; - - /* - * Do nothing if too soon since last collector start. This is a safety - * valve to protect against continuous respawn attempts if the collector - * is dying immediately at launch. Note that since we will be re-called - * from the postmaster main loop, we will get another chance later. - */ - curtime = time(NULL); - if ((unsigned int) (curtime - last_pgstat_start_time) < - (unsigned int) PGSTAT_RESTART_INTERVAL) - return 0; - last_pgstat_start_time = curtime; - - /* - * Okay, fork off the collector. - */ -#ifdef EXEC_BACKEND - switch ((pgStatPid = pgstat_forkexec())) -#else - switch ((pgStatPid = fork_process())) -#endif - { - case -1: - ereport(LOG, - (errmsg("could not fork statistics collector: %m"))); - return 0; - -#ifndef EXEC_BACKEND - case 0: - /* in postmaster child ... */ - InitPostmasterChild(); - - /* Close the postmaster's sockets */ - ClosePostmasterPorts(false); - - /* Drop our connection to postmaster's shared memory, as well */ - dsm_detach_all(); - PGSharedMemoryDetach(); - - PgstatCollectorMain(0, NULL); - break; -#endif - - default: - return (int) pgStatPid; - } - - /* shouldn't get here */ - return 0; -} - -void -allow_immediate_pgstat_restart(void) -{ - last_pgstat_start_time = 0; -} - -/* ------------------------------------------------------------ - * Public functions used by backends follow - *------------------------------------------------------------ - */ - - -/* ---------- - * pgstat_report_stat() - - * - * Must be called by processes that performs DML: tcop/postgres.c, logical - * receiver processes, SPI worker, etc. to send the so far collected - * per-table and function usage statistics to the collector. Note that this - * is called only when not within a transaction, so it is fair to use - * transaction stop time as an approximation of current time. - * - * "disconnect" is "true" only for the last call before the backend - * exits. This makes sure that no data is lost and that interrupted - * sessions are reported correctly. - * ---------- - */ -void -pgstat_report_stat(bool disconnect) -{ - /* we assume this inits to all zeroes: */ - static const PgStat_TableCounts all_zeroes; - static TimestampTz last_report = 0; - - TimestampTz now; - PgStat_MsgTabstat regular_msg; - PgStat_MsgTabstat shared_msg; - TabStatusArray *tsa; - int i; - - /* - * Don't expend a clock check if nothing to do. - * - * To determine whether any WAL activity has occurred since last time, not - * only the number of generated WAL records but also the numbers of WAL - * writes and syncs need to be checked. Because even transaction that - * generates no WAL records can write or sync WAL data when flushing the - * data pages. - */ - if ((pgStatTabList == NULL || pgStatTabList->tsa_used == 0) && - pgStatXactCommit == 0 && pgStatXactRollback == 0 && - pgWalUsage.wal_records == prevWalUsage.wal_records && - WalStats.m_wal_write == 0 && WalStats.m_wal_sync == 0 && - !have_function_stats && !disconnect) - return; - - /* - * Don't send a message unless it's been at least PGSTAT_STAT_INTERVAL - * msec since we last sent one, or the backend is about to exit. - */ - now = GetCurrentTransactionStopTimestamp(); - if (!disconnect && - !TimestampDifferenceExceeds(last_report, now, PGSTAT_STAT_INTERVAL)) - return; - - last_report = now; - - if (disconnect) - pgstat_report_disconnect(MyDatabaseId); - - /* - * Destroy pgStatTabHash before we start invalidating PgStat_TableEntry - * entries it points to. (Should we fail partway through the loop below, - * it's okay to have removed the hashtable already --- the only - * consequence is we'd get multiple entries for the same table in the - * pgStatTabList, and that's safe.) - */ - if (pgStatTabHash) - hash_destroy(pgStatTabHash); - pgStatTabHash = NULL; - - /* - * Scan through the TabStatusArray struct(s) to find tables that actually - * have counts, and build messages to send. We have to separate shared - * relations from regular ones because the databaseid field in the message - * header has to depend on that. - */ - regular_msg.m_databaseid = MyDatabaseId; - shared_msg.m_databaseid = InvalidOid; - regular_msg.m_nentries = 0; - shared_msg.m_nentries = 0; - - for (tsa = pgStatTabList; tsa != NULL; tsa = tsa->tsa_next) - { - for (i = 0; i < tsa->tsa_used; i++) - { - PgStat_TableStatus *entry = &tsa->tsa_entries[i]; - PgStat_MsgTabstat *this_msg; - PgStat_TableEntry *this_ent; - - /* Shouldn't have any pending transaction-dependent counts */ - Assert(entry->trans == NULL); - - /* - * Ignore entries that didn't accumulate any actual counts, such - * as indexes that were opened by the planner but not used. - */ - if (memcmp(&entry->t_counts, &all_zeroes, - sizeof(PgStat_TableCounts)) == 0) - continue; - - /* - * OK, insert data into the appropriate message, and send if full. - */ - this_msg = entry->t_shared ? &shared_msg : ®ular_msg; - this_ent = &this_msg->m_entry[this_msg->m_nentries]; - this_ent->t_id = entry->t_id; - memcpy(&this_ent->t_counts, &entry->t_counts, - sizeof(PgStat_TableCounts)); - if (++this_msg->m_nentries >= PGSTAT_NUM_TABENTRIES) - { - pgstat_send_tabstat(this_msg, now); - this_msg->m_nentries = 0; - } - } - /* zero out PgStat_TableStatus structs after use */ - MemSet(tsa->tsa_entries, 0, - tsa->tsa_used * sizeof(PgStat_TableStatus)); - tsa->tsa_used = 0; - } - - /* - * Send partial messages. Make sure that any pending xact commit/abort - * and connection stats get counted, even if there are no table stats to - * send. - */ - if (regular_msg.m_nentries > 0 || - pgStatXactCommit > 0 || pgStatXactRollback > 0 || disconnect) - pgstat_send_tabstat(®ular_msg, now); - if (shared_msg.m_nentries > 0) - pgstat_send_tabstat(&shared_msg, now); - - /* Now, send function statistics */ - pgstat_send_funcstats(); - - /* Send WAL statistics */ - pgstat_send_wal(true); - - /* Finally send SLRU statistics */ - pgstat_send_slru(); -} - -/* - * Subroutine for pgstat_report_stat: finish and send a tabstat message - */ -static void -pgstat_send_tabstat(PgStat_MsgTabstat *tsmsg, TimestampTz now) -{ - int n; - int len; - - /* It's unlikely we'd get here with no socket, but maybe not impossible */ - if (pgStatSock == PGINVALID_SOCKET) - return; - - /* - * Report and reset accumulated xact commit/rollback and I/O timings - * whenever we send a normal tabstat message - */ - if (OidIsValid(tsmsg->m_databaseid)) - { - tsmsg->m_xact_commit = pgStatXactCommit; - tsmsg->m_xact_rollback = pgStatXactRollback; - tsmsg->m_block_read_time = pgStatBlockReadTime; - tsmsg->m_block_write_time = pgStatBlockWriteTime; - - if (pgstat_should_report_connstat()) - { - long secs; - int usecs; - - /* - * pgLastSessionReportTime is initialized to MyStartTimestamp by - * pgstat_report_connect(). - */ - TimestampDifference(pgLastSessionReportTime, now, &secs, &usecs); - pgLastSessionReportTime = now; - tsmsg->m_session_time = (PgStat_Counter) secs * 1000000 + usecs; - tsmsg->m_active_time = pgStatActiveTime; - tsmsg->m_idle_in_xact_time = pgStatTransactionIdleTime; - } - else - { - tsmsg->m_session_time = 0; - tsmsg->m_active_time = 0; - tsmsg->m_idle_in_xact_time = 0; - } - pgStatXactCommit = 0; - pgStatXactRollback = 0; - pgStatBlockReadTime = 0; - pgStatBlockWriteTime = 0; - pgStatActiveTime = 0; - pgStatTransactionIdleTime = 0; - } - else - { - tsmsg->m_xact_commit = 0; - tsmsg->m_xact_rollback = 0; - tsmsg->m_block_read_time = 0; - tsmsg->m_block_write_time = 0; - tsmsg->m_session_time = 0; - tsmsg->m_active_time = 0; - tsmsg->m_idle_in_xact_time = 0; - } - - n = tsmsg->m_nentries; - len = offsetof(PgStat_MsgTabstat, m_entry[0]) + - n * sizeof(PgStat_TableEntry); - - pgstat_setheader(&tsmsg->m_hdr, PGSTAT_MTYPE_TABSTAT); - pgstat_send(tsmsg, len); -} - -/* - * Subroutine for pgstat_report_stat: populate and send a function stat message - */ -static void -pgstat_send_funcstats(void) -{ - /* we assume this inits to all zeroes: */ - static const PgStat_FunctionCounts all_zeroes; - - PgStat_MsgFuncstat msg; - PgStat_BackendFunctionEntry *entry; - HASH_SEQ_STATUS fstat; - - if (pgStatFunctions == NULL) - return; - - pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_FUNCSTAT); - msg.m_databaseid = MyDatabaseId; - msg.m_nentries = 0; - - hash_seq_init(&fstat, pgStatFunctions); - while ((entry = (PgStat_BackendFunctionEntry *) hash_seq_search(&fstat)) != NULL) - { - PgStat_FunctionEntry *m_ent; - - /* Skip it if no counts accumulated since last time */ - if (memcmp(&entry->f_counts, &all_zeroes, - sizeof(PgStat_FunctionCounts)) == 0) - continue; - - /* need to convert format of time accumulators */ - m_ent = &msg.m_entry[msg.m_nentries]; - m_ent->f_id = entry->f_id; - m_ent->f_numcalls = entry->f_counts.f_numcalls; - m_ent->f_total_time = INSTR_TIME_GET_MICROSEC(entry->f_counts.f_total_time); - m_ent->f_self_time = INSTR_TIME_GET_MICROSEC(entry->f_counts.f_self_time); - - if (++msg.m_nentries >= PGSTAT_NUM_FUNCENTRIES) - { - pgstat_send(&msg, offsetof(PgStat_MsgFuncstat, m_entry[0]) + - msg.m_nentries * sizeof(PgStat_FunctionEntry)); - msg.m_nentries = 0; - } - - /* reset the entry's counts */ - MemSet(&entry->f_counts, 0, sizeof(PgStat_FunctionCounts)); - } - - if (msg.m_nentries > 0) - pgstat_send(&msg, offsetof(PgStat_MsgFuncstat, m_entry[0]) + - msg.m_nentries * sizeof(PgStat_FunctionEntry)); - - have_function_stats = false; -} - - -/* ---------- - * pgstat_vacuum_stat() - - * - * Will tell the collector about objects he can get rid of. - * ---------- - */ -void -pgstat_vacuum_stat(void) -{ - HTAB *htab; - PgStat_MsgTabpurge msg; - PgStat_MsgFuncpurge f_msg; - HASH_SEQ_STATUS hstat; - PgStat_StatDBEntry *dbentry; - PgStat_StatTabEntry *tabentry; - PgStat_StatFuncEntry *funcentry; - int len; - - if (pgStatSock == PGINVALID_SOCKET) - return; - - /* - * If not done for this transaction, read the statistics collector stats - * file into some hash tables. - */ - backend_read_statsfile(); - - /* - * Read pg_database and make a list of OIDs of all existing databases - */ - htab = pgstat_collect_oids(DatabaseRelationId, Anum_pg_database_oid); - - /* - * Search the database hash table for dead databases and tell the - * collector to drop them. - */ - hash_seq_init(&hstat, pgStatDBHash); - while ((dbentry = (PgStat_StatDBEntry *) hash_seq_search(&hstat)) != NULL) - { - Oid dbid = dbentry->databaseid; - - CHECK_FOR_INTERRUPTS(); - - /* the DB entry for shared tables (with InvalidOid) is never dropped */ - if (OidIsValid(dbid) && - hash_search(htab, (void *) &dbid, HASH_FIND, NULL) == NULL) - pgstat_drop_database(dbid); - } - - /* Clean up */ - hash_destroy(htab); - - /* - * Search for all the dead replication slots in stats hashtable and tell - * the stats collector to drop them. - */ - if (replSlotStatHash) - { - PgStat_StatReplSlotEntry *slotentry; - - hash_seq_init(&hstat, replSlotStatHash); - while ((slotentry = (PgStat_StatReplSlotEntry *) hash_seq_search(&hstat)) != NULL) - { - CHECK_FOR_INTERRUPTS(); - - if (SearchNamedReplicationSlot(NameStr(slotentry->slotname), true) == NULL) - pgstat_report_replslot_drop(NameStr(slotentry->slotname)); - } - } - - /* - * Lookup our own database entry; if not found, nothing more to do. - */ - dbentry = (PgStat_StatDBEntry *) hash_search(pgStatDBHash, - (void *) &MyDatabaseId, - HASH_FIND, NULL); - if (dbentry == NULL || dbentry->tables == NULL) - return; - - /* - * Similarly to above, make a list of all known relations in this DB. - */ - htab = pgstat_collect_oids(RelationRelationId, Anum_pg_class_oid); - - /* - * Initialize our messages table counter to zero - */ - msg.m_nentries = 0; - - /* - * Check for all tables listed in stats hashtable if they still exist. - */ - hash_seq_init(&hstat, dbentry->tables); - while ((tabentry = (PgStat_StatTabEntry *) hash_seq_search(&hstat)) != NULL) - { - Oid tabid = tabentry->tableid; - - CHECK_FOR_INTERRUPTS(); - - if (hash_search(htab, (void *) &tabid, HASH_FIND, NULL) != NULL) - continue; - - /* - * Not there, so add this table's Oid to the message - */ - msg.m_tableid[msg.m_nentries++] = tabid; - - /* - * If the message is full, send it out and reinitialize to empty - */ - if (msg.m_nentries >= PGSTAT_NUM_TABPURGE) - { - len = offsetof(PgStat_MsgTabpurge, m_tableid[0]) - + msg.m_nentries * sizeof(Oid); - - pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_TABPURGE); - msg.m_databaseid = MyDatabaseId; - pgstat_send(&msg, len); - - msg.m_nentries = 0; - } - } - - /* - * Send the rest - */ - if (msg.m_nentries > 0) - { - len = offsetof(PgStat_MsgTabpurge, m_tableid[0]) - + msg.m_nentries * sizeof(Oid); - - pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_TABPURGE); - msg.m_databaseid = MyDatabaseId; - pgstat_send(&msg, len); - } - - /* Clean up */ - hash_destroy(htab); - - /* - * Now repeat the above steps for functions. However, we needn't bother - * in the common case where no function stats are being collected. - */ - if (dbentry->functions != NULL && - hash_get_num_entries(dbentry->functions) > 0) - { - htab = pgstat_collect_oids(ProcedureRelationId, Anum_pg_proc_oid); - - pgstat_setheader(&f_msg.m_hdr, PGSTAT_MTYPE_FUNCPURGE); - f_msg.m_databaseid = MyDatabaseId; - f_msg.m_nentries = 0; - - hash_seq_init(&hstat, dbentry->functions); - while ((funcentry = (PgStat_StatFuncEntry *) hash_seq_search(&hstat)) != NULL) - { - Oid funcid = funcentry->functionid; - - CHECK_FOR_INTERRUPTS(); - - if (hash_search(htab, (void *) &funcid, HASH_FIND, NULL) != NULL) - continue; - - /* - * Not there, so add this function's Oid to the message - */ - f_msg.m_functionid[f_msg.m_nentries++] = funcid; - - /* - * If the message is full, send it out and reinitialize to empty - */ - if (f_msg.m_nentries >= PGSTAT_NUM_FUNCPURGE) - { - len = offsetof(PgStat_MsgFuncpurge, m_functionid[0]) - + f_msg.m_nentries * sizeof(Oid); - - pgstat_send(&f_msg, len); - - f_msg.m_nentries = 0; - } - } - - /* - * Send the rest - */ - if (f_msg.m_nentries > 0) - { - len = offsetof(PgStat_MsgFuncpurge, m_functionid[0]) - + f_msg.m_nentries * sizeof(Oid); - - pgstat_send(&f_msg, len); - } - - hash_destroy(htab); - } -} - - -/* ---------- - * pgstat_collect_oids() - - * - * Collect the OIDs of all objects listed in the specified system catalog - * into a temporary hash table. Caller should hash_destroy the result - * when done with it. (However, we make the table in CurrentMemoryContext - * so that it will be freed properly in event of an error.) - * ---------- - */ -static HTAB * -pgstat_collect_oids(Oid catalogid, AttrNumber anum_oid) -{ - HTAB *htab; - HASHCTL hash_ctl; - Relation rel; - TableScanDesc scan; - HeapTuple tup; - Snapshot snapshot; - - hash_ctl.keysize = sizeof(Oid); - hash_ctl.entrysize = sizeof(Oid); - hash_ctl.hcxt = CurrentMemoryContext; - htab = hash_create("Temporary table of OIDs", - PGSTAT_TAB_HASH_SIZE, - &hash_ctl, - HASH_ELEM | HASH_BLOBS | HASH_CONTEXT); - - rel = table_open(catalogid, AccessShareLock); - snapshot = RegisterSnapshot(GetLatestSnapshot()); - scan = table_beginscan(rel, snapshot, 0, NULL); - while ((tup = heap_getnext(scan, ForwardScanDirection)) != NULL) - { - Oid thisoid; - bool isnull; - - thisoid = heap_getattr(tup, anum_oid, RelationGetDescr(rel), &isnull); - Assert(!isnull); - - CHECK_FOR_INTERRUPTS(); - - (void) hash_search(htab, (void *) &thisoid, HASH_ENTER, NULL); - } - table_endscan(scan); - UnregisterSnapshot(snapshot); - table_close(rel, AccessShareLock); - - return htab; -} - - -/* ---------- - * pgstat_drop_database() - - * - * Tell the collector that we just dropped a database. - * (If the message gets lost, we will still clean the dead DB eventually - * via future invocations of pgstat_vacuum_stat().) - * ---------- - */ -void -pgstat_drop_database(Oid databaseid) -{ - PgStat_MsgDropdb msg; - - if (pgStatSock == PGINVALID_SOCKET) - return; - - pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_DROPDB); - msg.m_databaseid = databaseid; - pgstat_send(&msg, sizeof(msg)); -} - - -/* ---------- - * pgstat_drop_relation() - - * - * Tell the collector that we just dropped a relation. - * (If the message gets lost, we will still clean the dead entry eventually - * via future invocations of pgstat_vacuum_stat().) - * - * Currently not used for lack of any good place to call it; we rely - * entirely on pgstat_vacuum_stat() to clean out stats for dead rels. - * ---------- - */ -#ifdef NOT_USED -void -pgstat_drop_relation(Oid relid) -{ - PgStat_MsgTabpurge msg; - int len; - - if (pgStatSock == PGINVALID_SOCKET) - return; - - msg.m_tableid[0] = relid; - msg.m_nentries = 1; - - len = offsetof(PgStat_MsgTabpurge, m_tableid[0]) + sizeof(Oid); - - pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_TABPURGE); - msg.m_databaseid = MyDatabaseId; - pgstat_send(&msg, len); -} -#endif /* NOT_USED */ - -/* ---------- - * pgstat_reset_counters() - - * - * Tell the statistics collector to reset counters for our database. - * - * Permission checking for this function is managed through the normal - * GRANT system. - * ---------- - */ -void -pgstat_reset_counters(void) -{ - PgStat_MsgResetcounter msg; - - if (pgStatSock == PGINVALID_SOCKET) - return; - - pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_RESETCOUNTER); - msg.m_databaseid = MyDatabaseId; - pgstat_send(&msg, sizeof(msg)); -} - -/* ---------- - * pgstat_reset_shared_counters() - - * - * Tell the statistics collector to reset cluster-wide shared counters. - * - * Permission checking for this function is managed through the normal - * GRANT system. - * ---------- - */ -void -pgstat_reset_shared_counters(const char *target) -{ - PgStat_MsgResetsharedcounter msg; - - if (pgStatSock == PGINVALID_SOCKET) - return; - - if (strcmp(target, "archiver") == 0) - msg.m_resettarget = RESET_ARCHIVER; - else if (strcmp(target, "bgwriter") == 0) - msg.m_resettarget = RESET_BGWRITER; - else if (strcmp(target, "wal") == 0) - msg.m_resettarget = RESET_WAL; - else - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("unrecognized reset target: \"%s\"", target), - errhint("Target must be \"archiver\", \"bgwriter\", or \"wal\"."))); - - pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_RESETSHAREDCOUNTER); - pgstat_send(&msg, sizeof(msg)); -} - -/* ---------- - * pgstat_reset_single_counter() - - * - * Tell the statistics collector to reset a single counter. - * - * Permission checking for this function is managed through the normal - * GRANT system. - * ---------- - */ -void -pgstat_reset_single_counter(Oid objoid, PgStat_Single_Reset_Type type) -{ - PgStat_MsgResetsinglecounter msg; - - if (pgStatSock == PGINVALID_SOCKET) - return; - - pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_RESETSINGLECOUNTER); - msg.m_databaseid = MyDatabaseId; - msg.m_resettype = type; - msg.m_objectid = objoid; - - pgstat_send(&msg, sizeof(msg)); -} - -/* ---------- - * pgstat_reset_slru_counter() - - * - * Tell the statistics collector to reset a single SLRU counter, or all - * SLRU counters (when name is null). - * - * Permission checking for this function is managed through the normal - * GRANT system. - * ---------- - */ -void -pgstat_reset_slru_counter(const char *name) -{ - PgStat_MsgResetslrucounter msg; - - if (pgStatSock == PGINVALID_SOCKET) - return; - - pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_RESETSLRUCOUNTER); - msg.m_index = (name) ? pgstat_slru_index(name) : -1; - - pgstat_send(&msg, sizeof(msg)); -} - -/* ---------- - * pgstat_reset_replslot_counter() - - * - * Tell the statistics collector to reset a single replication slot - * counter, or all replication slots counters (when name is null). - * - * Permission checking for this function is managed through the normal - * GRANT system. - * ---------- - */ -void -pgstat_reset_replslot_counter(const char *name) -{ - PgStat_MsgResetreplslotcounter msg; - - if (pgStatSock == PGINVALID_SOCKET) - return; - - if (name) - { - namestrcpy(&msg.m_slotname, name); - msg.clearall = false; - } - else - msg.clearall = true; - - pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_RESETREPLSLOTCOUNTER); - - pgstat_send(&msg, sizeof(msg)); -} - -/* ---------- - * pgstat_report_autovac() - - * - * Called from autovacuum.c to report startup of an autovacuum process. - * We are called before InitPostgres is done, so can't rely on MyDatabaseId; - * the db OID must be passed in, instead. - * ---------- - */ -void -pgstat_report_autovac(Oid dboid) -{ - PgStat_MsgAutovacStart msg; - - if (pgStatSock == PGINVALID_SOCKET) - return; - - pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_AUTOVAC_START); - msg.m_databaseid = dboid; - msg.m_start_time = GetCurrentTimestamp(); - - pgstat_send(&msg, sizeof(msg)); -} - - -/* --------- - * pgstat_report_vacuum() - - * - * Tell the collector about the table we just vacuumed. - * --------- - */ -void -pgstat_report_vacuum(Oid tableoid, bool shared, - PgStat_Counter livetuples, PgStat_Counter deadtuples) -{ - PgStat_MsgVacuum msg; - - if (pgStatSock == PGINVALID_SOCKET || !pgstat_track_counts) - return; - - pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_VACUUM); - msg.m_databaseid = shared ? InvalidOid : MyDatabaseId; - msg.m_tableoid = tableoid; - msg.m_autovacuum = IsAutoVacuumWorkerProcess(); - msg.m_vacuumtime = GetCurrentTimestamp(); - msg.m_live_tuples = livetuples; - msg.m_dead_tuples = deadtuples; - pgstat_send(&msg, sizeof(msg)); -} - -/* -------- - * pgstat_report_analyze() - - * - * Tell the collector about the table we just analyzed. - * - * Caller must provide new live- and dead-tuples estimates, as well as a - * flag indicating whether to reset the changes_since_analyze counter. - * -------- - */ -void -pgstat_report_analyze(Relation rel, - PgStat_Counter livetuples, PgStat_Counter deadtuples, - bool resetcounter) -{ - PgStat_MsgAnalyze msg; - - if (pgStatSock == PGINVALID_SOCKET || !pgstat_track_counts) - return; - - /* - * Unlike VACUUM, ANALYZE might be running inside a transaction that has - * already inserted and/or deleted rows in the target table. ANALYZE will - * have counted such rows as live or dead respectively. Because we will - * report our counts of such rows at transaction end, we should subtract - * off these counts from what we send to the collector now, else they'll - * be double-counted after commit. (This approach also ensures that the - * collector ends up with the right numbers if we abort instead of - * committing.) - * - * Waste no time on partitioned tables, though. - */ - if (rel->pgstat_info != NULL && - rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE) - { - PgStat_TableXactStatus *trans; - - for (trans = rel->pgstat_info->trans; trans; trans = trans->upper) - { - livetuples -= trans->tuples_inserted - trans->tuples_deleted; - deadtuples -= trans->tuples_updated + trans->tuples_deleted; - } - /* count stuff inserted by already-aborted subxacts, too */ - deadtuples -= rel->pgstat_info->t_counts.t_delta_dead_tuples; - /* Since ANALYZE's counts are estimates, we could have underflowed */ - livetuples = Max(livetuples, 0); - deadtuples = Max(deadtuples, 0); - } - - pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_ANALYZE); - msg.m_databaseid = rel->rd_rel->relisshared ? InvalidOid : MyDatabaseId; - msg.m_tableoid = RelationGetRelid(rel); - msg.m_autovacuum = IsAutoVacuumWorkerProcess(); - msg.m_resetcounter = resetcounter; - msg.m_analyzetime = GetCurrentTimestamp(); - msg.m_live_tuples = livetuples; - msg.m_dead_tuples = deadtuples; - pgstat_send(&msg, sizeof(msg)); -} - -/* -------- - * pgstat_report_recovery_conflict() - - * - * Tell the collector about a Hot Standby recovery conflict. - * -------- - */ -void -pgstat_report_recovery_conflict(int reason) -{ - PgStat_MsgRecoveryConflict msg; - - if (pgStatSock == PGINVALID_SOCKET || !pgstat_track_counts) - return; - - pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_RECOVERYCONFLICT); - msg.m_databaseid = MyDatabaseId; - msg.m_reason = reason; - pgstat_send(&msg, sizeof(msg)); -} - -/* -------- - * pgstat_report_deadlock() - - * - * Tell the collector about a deadlock detected. - * -------- - */ -void -pgstat_report_deadlock(void) -{ - PgStat_MsgDeadlock msg; - - if (pgStatSock == PGINVALID_SOCKET || !pgstat_track_counts) - return; - - pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_DEADLOCK); - msg.m_databaseid = MyDatabaseId; - pgstat_send(&msg, sizeof(msg)); -} - - - -/* -------- - * pgstat_report_checksum_failures_in_db() - - * - * Tell the collector about one or more checksum failures. - * -------- - */ -void -pgstat_report_checksum_failures_in_db(Oid dboid, int failurecount) -{ - PgStat_MsgChecksumFailure msg; - - if (pgStatSock == PGINVALID_SOCKET || !pgstat_track_counts) - return; - - pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_CHECKSUMFAILURE); - msg.m_databaseid = dboid; - msg.m_failurecount = failurecount; - msg.m_failure_time = GetCurrentTimestamp(); - - pgstat_send(&msg, sizeof(msg)); -} - -/* -------- - * pgstat_report_checksum_failure() - - * - * Tell the collector about a checksum failure. - * -------- - */ -void -pgstat_report_checksum_failure(void) -{ - pgstat_report_checksum_failures_in_db(MyDatabaseId, 1); -} - -/* -------- - * pgstat_report_tempfile() - - * - * Tell the collector about a temporary file. - * -------- - */ -void -pgstat_report_tempfile(size_t filesize) -{ - PgStat_MsgTempFile msg; - - if (pgStatSock == PGINVALID_SOCKET || !pgstat_track_counts) - return; - - pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_TEMPFILE); - msg.m_databaseid = MyDatabaseId; - msg.m_filesize = filesize; - pgstat_send(&msg, sizeof(msg)); -} - -/* -------- - * pgstat_report_connect() - - * - * Tell the collector about a new connection. - * -------- - */ -void -pgstat_report_connect(Oid dboid) -{ - PgStat_MsgConnect msg; - - if (!pgstat_should_report_connstat()) - return; - - pgLastSessionReportTime = MyStartTimestamp; - - pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_CONNECT); - msg.m_databaseid = MyDatabaseId; - pgstat_send(&msg, sizeof(PgStat_MsgConnect)); -} - -/* -------- - * pgstat_report_disconnect() - - * - * Tell the collector about a disconnect. - * -------- - */ -static void -pgstat_report_disconnect(Oid dboid) -{ - PgStat_MsgDisconnect msg; - - if (!pgstat_should_report_connstat()) - return; - - pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_DISCONNECT); - msg.m_databaseid = MyDatabaseId; - msg.m_cause = pgStatSessionEndCause; - pgstat_send(&msg, sizeof(PgStat_MsgDisconnect)); -} - -/* -------- - * pgstat_should_report_connstats() - - * - * We report session statistics only for normal backend processes. Parallel - * workers run in parallel, so they don't contribute to session times, even - * though they use CPU time. Walsender processes could be considered here, - * but they have different session characteristics from normal backends (for - * example, they are always "active"), so they would skew session statistics. - * ---------- - */ -static bool -pgstat_should_report_connstat(void) -{ - return MyBackendType == B_BACKEND; -} - -/* ---------- - * pgstat_report_replslot() - - * - * Tell the collector about replication slot statistics. - * ---------- - */ -void -pgstat_report_replslot(const PgStat_StatReplSlotEntry *repSlotStat) -{ - PgStat_MsgReplSlot msg; - - /* - * Prepare and send the message - */ - pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_REPLSLOT); - namestrcpy(&msg.m_slotname, NameStr(repSlotStat->slotname)); - msg.m_create = false; - msg.m_drop = false; - msg.m_spill_txns = repSlotStat->spill_txns; - msg.m_spill_count = repSlotStat->spill_count; - msg.m_spill_bytes = repSlotStat->spill_bytes; - msg.m_stream_txns = repSlotStat->stream_txns; - msg.m_stream_count = repSlotStat->stream_count; - msg.m_stream_bytes = repSlotStat->stream_bytes; - msg.m_total_txns = repSlotStat->total_txns; - msg.m_total_bytes = repSlotStat->total_bytes; - pgstat_send(&msg, sizeof(PgStat_MsgReplSlot)); -} - -/* ---------- - * pgstat_report_replslot_create() - - * - * Tell the collector about creating the replication slot. - * ---------- - */ -void -pgstat_report_replslot_create(const char *slotname) -{ - PgStat_MsgReplSlot msg; - - pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_REPLSLOT); - namestrcpy(&msg.m_slotname, slotname); - msg.m_create = true; - msg.m_drop = false; - pgstat_send(&msg, sizeof(PgStat_MsgReplSlot)); -} - -/* ---------- - * pgstat_report_replslot_drop() - - * - * Tell the collector about dropping the replication slot. - * ---------- - */ -void -pgstat_report_replslot_drop(const char *slotname) -{ - PgStat_MsgReplSlot msg; - - pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_REPLSLOT); - namestrcpy(&msg.m_slotname, slotname); - msg.m_create = false; - msg.m_drop = true; - pgstat_send(&msg, sizeof(PgStat_MsgReplSlot)); -} - -/* ---------- - * pgstat_ping() - - * - * Send some junk data to the collector to increase traffic. - * ---------- - */ -void -pgstat_ping(void) -{ - PgStat_MsgDummy msg; - - if (pgStatSock == PGINVALID_SOCKET) - return; - - pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_DUMMY); - pgstat_send(&msg, sizeof(msg)); -} - -/* ---------- - * pgstat_send_inquiry() - - * - * Notify collector that we need fresh data. - * ---------- - */ -static void -pgstat_send_inquiry(TimestampTz clock_time, TimestampTz cutoff_time, Oid databaseid) -{ - PgStat_MsgInquiry msg; - - pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_INQUIRY); - msg.clock_time = clock_time; - msg.cutoff_time = cutoff_time; - msg.databaseid = databaseid; - pgstat_send(&msg, sizeof(msg)); -} - - -/* - * Initialize function call usage data. - * Called by the executor before invoking a function. - */ -void -pgstat_init_function_usage(FunctionCallInfo fcinfo, - PgStat_FunctionCallUsage *fcu) -{ - PgStat_BackendFunctionEntry *htabent; - bool found; - - if (pgstat_track_functions <= fcinfo->flinfo->fn_stats) - { - /* stats not wanted */ - fcu->fs = NULL; - return; - } - - if (!pgStatFunctions) - { - /* First time through - initialize function stat table */ - HASHCTL hash_ctl; - - hash_ctl.keysize = sizeof(Oid); - hash_ctl.entrysize = sizeof(PgStat_BackendFunctionEntry); - pgStatFunctions = hash_create("Function stat entries", - PGSTAT_FUNCTION_HASH_SIZE, - &hash_ctl, - HASH_ELEM | HASH_BLOBS); - } - - /* Get the stats entry for this function, create if necessary */ - htabent = hash_search(pgStatFunctions, &fcinfo->flinfo->fn_oid, - HASH_ENTER, &found); - if (!found) - MemSet(&htabent->f_counts, 0, sizeof(PgStat_FunctionCounts)); - - fcu->fs = &htabent->f_counts; - - /* save stats for this function, later used to compensate for recursion */ - fcu->save_f_total_time = htabent->f_counts.f_total_time; - - /* save current backend-wide total time */ - fcu->save_total = total_func_time; - - /* get clock time as of function start */ - INSTR_TIME_SET_CURRENT(fcu->f_start); -} - -/* - * find_funcstat_entry - find any existing PgStat_BackendFunctionEntry entry - * for specified function - * - * If no entry, return NULL, don't create a new one - */ -PgStat_BackendFunctionEntry * -find_funcstat_entry(Oid func_id) -{ - if (pgStatFunctions == NULL) - return NULL; - - return (PgStat_BackendFunctionEntry *) hash_search(pgStatFunctions, - (void *) &func_id, - HASH_FIND, NULL); -} - -/* - * Calculate function call usage and update stat counters. - * Called by the executor after invoking a function. - * - * In the case of a set-returning function that runs in value-per-call mode, - * we will see multiple pgstat_init_function_usage/pgstat_end_function_usage - * calls for what the user considers a single call of the function. The - * finalize flag should be TRUE on the last call. - */ -void -pgstat_end_function_usage(PgStat_FunctionCallUsage *fcu, bool finalize) -{ - PgStat_FunctionCounts *fs = fcu->fs; - instr_time f_total; - instr_time f_others; - instr_time f_self; - - /* stats not wanted? */ - if (fs == NULL) - return; - - /* total elapsed time in this function call */ - INSTR_TIME_SET_CURRENT(f_total); - INSTR_TIME_SUBTRACT(f_total, fcu->f_start); - - /* self usage: elapsed minus anything already charged to other calls */ - f_others = total_func_time; - INSTR_TIME_SUBTRACT(f_others, fcu->save_total); - f_self = f_total; - INSTR_TIME_SUBTRACT(f_self, f_others); - - /* update backend-wide total time */ - INSTR_TIME_ADD(total_func_time, f_self); - - /* - * Compute the new f_total_time as the total elapsed time added to the - * pre-call value of f_total_time. This is necessary to avoid - * double-counting any time taken by recursive calls of myself. (We do - * not need any similar kluge for self time, since that already excludes - * any recursive calls.) - */ - INSTR_TIME_ADD(f_total, fcu->save_f_total_time); - - /* update counters in function stats table */ - if (finalize) - fs->f_numcalls++; - fs->f_total_time = f_total; - INSTR_TIME_ADD(fs->f_self_time, f_self); - - /* indicate that we have something to send */ - have_function_stats = true; -} - - -/* ---------- - * pgstat_initstats() - - * - * Initialize a relcache entry to count access statistics. - * Called whenever a relation is opened. - * - * We assume that a relcache entry's pgstat_info field is zeroed by - * relcache.c when the relcache entry is made; thereafter it is long-lived - * data. We can avoid repeated searches of the TabStatus arrays when the - * same relation is touched repeatedly within a transaction. - * ---------- - */ -void -pgstat_initstats(Relation rel) -{ - Oid rel_id = rel->rd_id; - char relkind = rel->rd_rel->relkind; - - /* - * We only count stats for relations with storage and partitioned tables - */ - if (!RELKIND_HAS_STORAGE(relkind) && relkind != RELKIND_PARTITIONED_TABLE) - { - rel->pgstat_info = NULL; - return; - } - - if (pgStatSock == PGINVALID_SOCKET || !pgstat_track_counts) - { - /* We're not counting at all */ - rel->pgstat_info = NULL; - return; - } - - /* - * If we already set up this relation in the current transaction, nothing - * to do. - */ - if (rel->pgstat_info != NULL && - rel->pgstat_info->t_id == rel_id) - return; - - /* Else find or make the PgStat_TableStatus entry, and update link */ - rel->pgstat_info = get_tabstat_entry(rel_id, rel->rd_rel->relisshared); -} - -/* - * get_tabstat_entry - find or create a PgStat_TableStatus entry for rel - */ -static PgStat_TableStatus * -get_tabstat_entry(Oid rel_id, bool isshared) -{ - TabStatHashEntry *hash_entry; - PgStat_TableStatus *entry; - TabStatusArray *tsa; - bool found; - - /* - * Create hash table if we don't have it already. - */ - if (pgStatTabHash == NULL) - { - HASHCTL ctl; - - ctl.keysize = sizeof(Oid); - ctl.entrysize = sizeof(TabStatHashEntry); - - pgStatTabHash = hash_create("pgstat TabStatusArray lookup hash table", - TABSTAT_QUANTUM, - &ctl, - HASH_ELEM | HASH_BLOBS); - } - - /* - * Find an entry or create a new one. - */ - hash_entry = hash_search(pgStatTabHash, &rel_id, HASH_ENTER, &found); - if (!found) - { - /* initialize new entry with null pointer */ - hash_entry->tsa_entry = NULL; - } - - /* - * If entry is already valid, we're done. - */ - if (hash_entry->tsa_entry) - return hash_entry->tsa_entry; - - /* - * Locate the first pgStatTabList entry with free space, making a new list - * entry if needed. Note that we could get an OOM failure here, but if so - * we have left the hashtable and the list in a consistent state. - */ - if (pgStatTabList == NULL) - { - /* Set up first pgStatTabList entry */ - pgStatTabList = (TabStatusArray *) - MemoryContextAllocZero(TopMemoryContext, - sizeof(TabStatusArray)); - } - - tsa = pgStatTabList; - while (tsa->tsa_used >= TABSTAT_QUANTUM) - { - if (tsa->tsa_next == NULL) - tsa->tsa_next = (TabStatusArray *) - MemoryContextAllocZero(TopMemoryContext, - sizeof(TabStatusArray)); - tsa = tsa->tsa_next; - } - - /* - * Allocate a PgStat_TableStatus entry within this list entry. We assume - * the entry was already zeroed, either at creation or after last use. - */ - entry = &tsa->tsa_entries[tsa->tsa_used++]; - entry->t_id = rel_id; - entry->t_shared = isshared; - - /* - * Now we can fill the entry in pgStatTabHash. - */ - hash_entry->tsa_entry = entry; - - return entry; -} - -/* - * find_tabstat_entry - find any existing PgStat_TableStatus entry for rel - * - * If no entry, return NULL, don't create a new one - * - * Note: if we got an error in the most recent execution of pgstat_report_stat, - * it's possible that an entry exists but there's no hashtable entry for it. - * That's okay, we'll treat this case as "doesn't exist". - */ -PgStat_TableStatus * -find_tabstat_entry(Oid rel_id) -{ - TabStatHashEntry *hash_entry; - - /* If hashtable doesn't exist, there are no entries at all */ - if (!pgStatTabHash) - return NULL; - - hash_entry = hash_search(pgStatTabHash, &rel_id, HASH_FIND, NULL); - if (!hash_entry) - return NULL; - - /* Note that this step could also return NULL, but that's correct */ - return hash_entry->tsa_entry; -} - -/* - * get_tabstat_stack_level - add a new (sub)transaction stack entry if needed - */ -static PgStat_SubXactStatus * -get_tabstat_stack_level(int nest_level) -{ - PgStat_SubXactStatus *xact_state; - - xact_state = pgStatXactStack; - if (xact_state == NULL || xact_state->nest_level != nest_level) - { - xact_state = (PgStat_SubXactStatus *) - MemoryContextAlloc(TopTransactionContext, - sizeof(PgStat_SubXactStatus)); - xact_state->nest_level = nest_level; - xact_state->prev = pgStatXactStack; - xact_state->first = NULL; - pgStatXactStack = xact_state; - } - return xact_state; -} - -/* - * add_tabstat_xact_level - add a new (sub)transaction state record - */ -static void -add_tabstat_xact_level(PgStat_TableStatus *pgstat_info, int nest_level) -{ - PgStat_SubXactStatus *xact_state; - PgStat_TableXactStatus *trans; - - /* - * If this is the first rel to be modified at the current nest level, we - * first have to push a transaction stack entry. - */ - xact_state = get_tabstat_stack_level(nest_level); - - /* Now make a per-table stack entry */ - trans = (PgStat_TableXactStatus *) - MemoryContextAllocZero(TopTransactionContext, - sizeof(PgStat_TableXactStatus)); - trans->nest_level = nest_level; - trans->upper = pgstat_info->trans; - trans->parent = pgstat_info; - trans->next = xact_state->first; - xact_state->first = trans; - pgstat_info->trans = trans; -} - -/* - * pgstat_count_heap_insert - count a tuple insertion of n tuples - */ -void -pgstat_count_heap_insert(Relation rel, PgStat_Counter n) -{ - PgStat_TableStatus *pgstat_info = rel->pgstat_info; - - if (pgstat_info != NULL) - { - /* We have to log the effect at the proper transactional level */ - int nest_level = GetCurrentTransactionNestLevel(); - - if (pgstat_info->trans == NULL || - pgstat_info->trans->nest_level != nest_level) - add_tabstat_xact_level(pgstat_info, nest_level); - - pgstat_info->trans->tuples_inserted += n; - } -} - -/* - * pgstat_count_heap_update - count a tuple update - */ -void -pgstat_count_heap_update(Relation rel, bool hot) -{ - PgStat_TableStatus *pgstat_info = rel->pgstat_info; - - if (pgstat_info != NULL) - { - /* We have to log the effect at the proper transactional level */ - int nest_level = GetCurrentTransactionNestLevel(); - - if (pgstat_info->trans == NULL || - pgstat_info->trans->nest_level != nest_level) - add_tabstat_xact_level(pgstat_info, nest_level); - - pgstat_info->trans->tuples_updated++; - - /* t_tuples_hot_updated is nontransactional, so just advance it */ - if (hot) - pgstat_info->t_counts.t_tuples_hot_updated++; - } -} - -/* - * pgstat_count_heap_delete - count a tuple deletion - */ -void -pgstat_count_heap_delete(Relation rel) -{ - PgStat_TableStatus *pgstat_info = rel->pgstat_info; - - if (pgstat_info != NULL) - { - /* We have to log the effect at the proper transactional level */ - int nest_level = GetCurrentTransactionNestLevel(); - - if (pgstat_info->trans == NULL || - pgstat_info->trans->nest_level != nest_level) - add_tabstat_xact_level(pgstat_info, nest_level); - - pgstat_info->trans->tuples_deleted++; - } -} - -/* - * pgstat_truncate_save_counters - * - * Whenever a table is truncated, we save its i/u/d counters so that they can - * be cleared, and if the (sub)xact that executed the truncate later aborts, - * the counters can be restored to the saved (pre-truncate) values. Note we do - * this on the first truncate in any particular subxact level only. - */ -static void -pgstat_truncate_save_counters(PgStat_TableXactStatus *trans) -{ - if (!trans->truncated) - { - trans->inserted_pre_trunc = trans->tuples_inserted; - trans->updated_pre_trunc = trans->tuples_updated; - trans->deleted_pre_trunc = trans->tuples_deleted; - trans->truncated = true; - } -} - -/* - * pgstat_truncate_restore_counters - restore counters when a truncate aborts - */ -static void -pgstat_truncate_restore_counters(PgStat_TableXactStatus *trans) -{ - if (trans->truncated) - { - trans->tuples_inserted = trans->inserted_pre_trunc; - trans->tuples_updated = trans->updated_pre_trunc; - trans->tuples_deleted = trans->deleted_pre_trunc; - } -} - -/* - * pgstat_count_truncate - update tuple counters due to truncate - */ -void -pgstat_count_truncate(Relation rel) -{ - PgStat_TableStatus *pgstat_info = rel->pgstat_info; - - if (pgstat_info != NULL) - { - /* We have to log the effect at the proper transactional level */ - int nest_level = GetCurrentTransactionNestLevel(); - - if (pgstat_info->trans == NULL || - pgstat_info->trans->nest_level != nest_level) - add_tabstat_xact_level(pgstat_info, nest_level); - - pgstat_truncate_save_counters(pgstat_info->trans); - pgstat_info->trans->tuples_inserted = 0; - pgstat_info->trans->tuples_updated = 0; - pgstat_info->trans->tuples_deleted = 0; - } -} - -/* - * pgstat_update_heap_dead_tuples - update dead-tuples count - * - * The semantics of this are that we are reporting the nontransactional - * recovery of "delta" dead tuples; so t_delta_dead_tuples decreases - * rather than increasing, and the change goes straight into the per-table - * counter, not into transactional state. - */ -void -pgstat_update_heap_dead_tuples(Relation rel, int delta) -{ - PgStat_TableStatus *pgstat_info = rel->pgstat_info; - - if (pgstat_info != NULL) - pgstat_info->t_counts.t_delta_dead_tuples -= delta; -} - - -/* ---------- - * AtEOXact_PgStat - * - * Called from access/transam/xact.c at top-level transaction commit/abort. - * ---------- - */ -void -AtEOXact_PgStat(bool isCommit, bool parallel) -{ - PgStat_SubXactStatus *xact_state; - - /* Don't count parallel worker transaction stats */ - if (!parallel) - { - /* - * Count transaction commit or abort. (We use counters, not just - * bools, in case the reporting message isn't sent right away.) - */ - if (isCommit) - pgStatXactCommit++; - else - pgStatXactRollback++; - } - - /* - * Transfer transactional insert/update counts into the base tabstat - * entries. We don't bother to free any of the transactional state, since - * it's all in TopTransactionContext and will go away anyway. - */ - xact_state = pgStatXactStack; - if (xact_state != NULL) - { - PgStat_TableXactStatus *trans; - - Assert(xact_state->nest_level == 1); - Assert(xact_state->prev == NULL); - for (trans = xact_state->first; trans != NULL; trans = trans->next) - { - PgStat_TableStatus *tabstat; - - Assert(trans->nest_level == 1); - Assert(trans->upper == NULL); - tabstat = trans->parent; - Assert(tabstat->trans == trans); - /* restore pre-truncate stats (if any) in case of aborted xact */ - if (!isCommit) - pgstat_truncate_restore_counters(trans); - /* count attempted actions regardless of commit/abort */ - tabstat->t_counts.t_tuples_inserted += trans->tuples_inserted; - tabstat->t_counts.t_tuples_updated += trans->tuples_updated; - tabstat->t_counts.t_tuples_deleted += trans->tuples_deleted; - if (isCommit) - { - tabstat->t_counts.t_truncated = trans->truncated; - if (trans->truncated) - { - /* forget live/dead stats seen by backend thus far */ - tabstat->t_counts.t_delta_live_tuples = 0; - tabstat->t_counts.t_delta_dead_tuples = 0; - } - /* insert adds a live tuple, delete removes one */ - tabstat->t_counts.t_delta_live_tuples += - trans->tuples_inserted - trans->tuples_deleted; - /* update and delete each create a dead tuple */ - tabstat->t_counts.t_delta_dead_tuples += - trans->tuples_updated + trans->tuples_deleted; - /* insert, update, delete each count as one change event */ - tabstat->t_counts.t_changed_tuples += - trans->tuples_inserted + trans->tuples_updated + - trans->tuples_deleted; - } - else - { - /* inserted tuples are dead, deleted tuples are unaffected */ - tabstat->t_counts.t_delta_dead_tuples += - trans->tuples_inserted + trans->tuples_updated; - /* an aborted xact generates no changed_tuple events */ - } - tabstat->trans = NULL; - } - } - pgStatXactStack = NULL; - - /* Make sure any stats snapshot is thrown away */ - pgstat_clear_snapshot(); -} - -/* ---------- - * AtEOSubXact_PgStat - * - * Called from access/transam/xact.c at subtransaction commit/abort. - * ---------- - */ -void -AtEOSubXact_PgStat(bool isCommit, int nestDepth) -{ - PgStat_SubXactStatus *xact_state; - - /* - * Transfer transactional insert/update counts into the next higher - * subtransaction state. - */ - xact_state = pgStatXactStack; - if (xact_state != NULL && - xact_state->nest_level >= nestDepth) - { - PgStat_TableXactStatus *trans; - PgStat_TableXactStatus *next_trans; - - /* delink xact_state from stack immediately to simplify reuse case */ - pgStatXactStack = xact_state->prev; - - for (trans = xact_state->first; trans != NULL; trans = next_trans) - { - PgStat_TableStatus *tabstat; - - next_trans = trans->next; - Assert(trans->nest_level == nestDepth); - tabstat = trans->parent; - Assert(tabstat->trans == trans); - if (isCommit) - { - if (trans->upper && trans->upper->nest_level == nestDepth - 1) - { - if (trans->truncated) - { - /* propagate the truncate status one level up */ - pgstat_truncate_save_counters(trans->upper); - /* replace upper xact stats with ours */ - trans->upper->tuples_inserted = trans->tuples_inserted; - trans->upper->tuples_updated = trans->tuples_updated; - trans->upper->tuples_deleted = trans->tuples_deleted; - } - else - { - trans->upper->tuples_inserted += trans->tuples_inserted; - trans->upper->tuples_updated += trans->tuples_updated; - trans->upper->tuples_deleted += trans->tuples_deleted; - } - tabstat->trans = trans->upper; - pfree(trans); - } - else - { - /* - * When there isn't an immediate parent state, we can just - * reuse the record instead of going through a - * palloc/pfree pushup (this works since it's all in - * TopTransactionContext anyway). We have to re-link it - * into the parent level, though, and that might mean - * pushing a new entry into the pgStatXactStack. - */ - PgStat_SubXactStatus *upper_xact_state; - - upper_xact_state = get_tabstat_stack_level(nestDepth - 1); - trans->next = upper_xact_state->first; - upper_xact_state->first = trans; - trans->nest_level = nestDepth - 1; - } - } - else - { - /* - * On abort, update top-level tabstat counts, then forget the - * subtransaction - */ - - /* first restore values obliterated by truncate */ - pgstat_truncate_restore_counters(trans); - /* count attempted actions regardless of commit/abort */ - tabstat->t_counts.t_tuples_inserted += trans->tuples_inserted; - tabstat->t_counts.t_tuples_updated += trans->tuples_updated; - tabstat->t_counts.t_tuples_deleted += trans->tuples_deleted; - /* inserted tuples are dead, deleted tuples are unaffected */ - tabstat->t_counts.t_delta_dead_tuples += - trans->tuples_inserted + trans->tuples_updated; - tabstat->trans = trans->upper; - pfree(trans); - } - } - pfree(xact_state); - } -} - - -/* - * AtPrepare_PgStat - * Save the transactional stats state at 2PC transaction prepare. - * - * In this phase we just generate 2PC records for all the pending - * transaction-dependent stats work. - */ -void -AtPrepare_PgStat(void) -{ - PgStat_SubXactStatus *xact_state; - - xact_state = pgStatXactStack; - if (xact_state != NULL) - { - PgStat_TableXactStatus *trans; - - Assert(xact_state->nest_level == 1); - Assert(xact_state->prev == NULL); - for (trans = xact_state->first; trans != NULL; trans = trans->next) - { - PgStat_TableStatus *tabstat; - TwoPhasePgStatRecord record; - - Assert(trans->nest_level == 1); - Assert(trans->upper == NULL); - tabstat = trans->parent; - Assert(tabstat->trans == trans); - - record.tuples_inserted = trans->tuples_inserted; - record.tuples_updated = trans->tuples_updated; - record.tuples_deleted = trans->tuples_deleted; - record.inserted_pre_trunc = trans->inserted_pre_trunc; - record.updated_pre_trunc = trans->updated_pre_trunc; - record.deleted_pre_trunc = trans->deleted_pre_trunc; - record.t_id = tabstat->t_id; - record.t_shared = tabstat->t_shared; - record.t_truncated = trans->truncated; - - RegisterTwoPhaseRecord(TWOPHASE_RM_PGSTAT_ID, 0, - &record, sizeof(TwoPhasePgStatRecord)); - } - } -} - -/* - * PostPrepare_PgStat - * Clean up after successful PREPARE. - * - * All we need do here is unlink the transaction stats state from the - * nontransactional state. The nontransactional action counts will be - * reported to the stats collector immediately, while the effects on live - * and dead tuple counts are preserved in the 2PC state file. - * - * Note: AtEOXact_PgStat is not called during PREPARE. - */ -void -PostPrepare_PgStat(void) -{ - PgStat_SubXactStatus *xact_state; - - /* - * We don't bother to free any of the transactional state, since it's all - * in TopTransactionContext and will go away anyway. - */ - xact_state = pgStatXactStack; - if (xact_state != NULL) - { - PgStat_TableXactStatus *trans; - - for (trans = xact_state->first; trans != NULL; trans = trans->next) - { - PgStat_TableStatus *tabstat; - - tabstat = trans->parent; - tabstat->trans = NULL; - } - } - pgStatXactStack = NULL; - - /* Make sure any stats snapshot is thrown away */ - pgstat_clear_snapshot(); -} - -/* - * 2PC processing routine for COMMIT PREPARED case. - * - * Load the saved counts into our local pgstats state. - */ -void -pgstat_twophase_postcommit(TransactionId xid, uint16 info, - void *recdata, uint32 len) -{ - TwoPhasePgStatRecord *rec = (TwoPhasePgStatRecord *) recdata; - PgStat_TableStatus *pgstat_info; - - /* Find or create a tabstat entry for the rel */ - pgstat_info = get_tabstat_entry(rec->t_id, rec->t_shared); - - /* Same math as in AtEOXact_PgStat, commit case */ - pgstat_info->t_counts.t_tuples_inserted += rec->tuples_inserted; - pgstat_info->t_counts.t_tuples_updated += rec->tuples_updated; - pgstat_info->t_counts.t_tuples_deleted += rec->tuples_deleted; - pgstat_info->t_counts.t_truncated = rec->t_truncated; - if (rec->t_truncated) - { - /* forget live/dead stats seen by backend thus far */ - pgstat_info->t_counts.t_delta_live_tuples = 0; - pgstat_info->t_counts.t_delta_dead_tuples = 0; - } - pgstat_info->t_counts.t_delta_live_tuples += - rec->tuples_inserted - rec->tuples_deleted; - pgstat_info->t_counts.t_delta_dead_tuples += - rec->tuples_updated + rec->tuples_deleted; - pgstat_info->t_counts.t_changed_tuples += - rec->tuples_inserted + rec->tuples_updated + - rec->tuples_deleted; -} - -/* - * 2PC processing routine for ROLLBACK PREPARED case. - * - * Load the saved counts into our local pgstats state, but treat them - * as aborted. - */ -void -pgstat_twophase_postabort(TransactionId xid, uint16 info, - void *recdata, uint32 len) -{ - TwoPhasePgStatRecord *rec = (TwoPhasePgStatRecord *) recdata; - PgStat_TableStatus *pgstat_info; - - /* Find or create a tabstat entry for the rel */ - pgstat_info = get_tabstat_entry(rec->t_id, rec->t_shared); - - /* Same math as in AtEOXact_PgStat, abort case */ - if (rec->t_truncated) - { - rec->tuples_inserted = rec->inserted_pre_trunc; - rec->tuples_updated = rec->updated_pre_trunc; - rec->tuples_deleted = rec->deleted_pre_trunc; - } - pgstat_info->t_counts.t_tuples_inserted += rec->tuples_inserted; - pgstat_info->t_counts.t_tuples_updated += rec->tuples_updated; - pgstat_info->t_counts.t_tuples_deleted += rec->tuples_deleted; - pgstat_info->t_counts.t_delta_dead_tuples += - rec->tuples_inserted + rec->tuples_updated; -} - - -/* ---------- - * pgstat_fetch_stat_dbentry() - - * - * Support function for the SQL-callable pgstat* functions. Returns - * the collected statistics for one database or NULL. NULL doesn't mean - * that the database doesn't exist, it is just not yet known by the - * collector, so the caller is better off to report ZERO instead. - * ---------- - */ -PgStat_StatDBEntry * -pgstat_fetch_stat_dbentry(Oid dbid) -{ - /* - * If not done for this transaction, read the statistics collector stats - * file into some hash tables. - */ - backend_read_statsfile(); - - /* - * Lookup the requested database; return NULL if not found - */ - return (PgStat_StatDBEntry *) hash_search(pgStatDBHash, - (void *) &dbid, - HASH_FIND, NULL); -} - - -/* ---------- - * pgstat_fetch_stat_tabentry() - - * - * Support function for the SQL-callable pgstat* functions. Returns - * the collected statistics for one table or NULL. NULL doesn't mean - * that the table doesn't exist, it is just not yet known by the - * collector, so the caller is better off to report ZERO instead. - * ---------- - */ -PgStat_StatTabEntry * -pgstat_fetch_stat_tabentry(Oid relid) -{ - Oid dbid; - PgStat_StatDBEntry *dbentry; - PgStat_StatTabEntry *tabentry; - - /* - * If not done for this transaction, read the statistics collector stats - * file into some hash tables. - */ - backend_read_statsfile(); - - /* - * Lookup our database, then look in its table hash table. - */ - dbid = MyDatabaseId; - dbentry = (PgStat_StatDBEntry *) hash_search(pgStatDBHash, - (void *) &dbid, - HASH_FIND, NULL); - if (dbentry != NULL && dbentry->tables != NULL) - { - tabentry = (PgStat_StatTabEntry *) hash_search(dbentry->tables, - (void *) &relid, - HASH_FIND, NULL); - if (tabentry) - return tabentry; - } - - /* - * If we didn't find it, maybe it's a shared table. - */ - dbid = InvalidOid; - dbentry = (PgStat_StatDBEntry *) hash_search(pgStatDBHash, - (void *) &dbid, - HASH_FIND, NULL); - if (dbentry != NULL && dbentry->tables != NULL) - { - tabentry = (PgStat_StatTabEntry *) hash_search(dbentry->tables, - (void *) &relid, - HASH_FIND, NULL); - if (tabentry) - return tabentry; - } - - return NULL; -} - - -/* ---------- - * pgstat_fetch_stat_funcentry() - - * - * Support function for the SQL-callable pgstat* functions. Returns - * the collected statistics for one function or NULL. - * ---------- - */ -PgStat_StatFuncEntry * -pgstat_fetch_stat_funcentry(Oid func_id) -{ - PgStat_StatDBEntry *dbentry; - PgStat_StatFuncEntry *funcentry = NULL; - - /* load the stats file if needed */ - backend_read_statsfile(); - - /* Lookup our database, then find the requested function. */ - dbentry = pgstat_fetch_stat_dbentry(MyDatabaseId); - if (dbentry != NULL && dbentry->functions != NULL) - { - funcentry = (PgStat_StatFuncEntry *) hash_search(dbentry->functions, - (void *) &func_id, - HASH_FIND, NULL); - } - - return funcentry; -} - - -/* - * --------- - * pgstat_fetch_stat_archiver() - - * - * Support function for the SQL-callable pgstat* functions. Returns - * a pointer to the archiver statistics struct. - * --------- - */ -PgStat_ArchiverStats * -pgstat_fetch_stat_archiver(void) -{ - backend_read_statsfile(); - - return &archiverStats; -} - - -/* - * --------- - * pgstat_fetch_global() - - * - * Support function for the SQL-callable pgstat* functions. Returns - * a pointer to the global statistics struct. - * --------- - */ -PgStat_GlobalStats * -pgstat_fetch_global(void) -{ - backend_read_statsfile(); - - return &globalStats; -} - -/* - * --------- - * pgstat_fetch_stat_wal() - - * - * Support function for the SQL-callable pgstat* functions. Returns - * a pointer to the WAL statistics struct. - * --------- - */ -PgStat_WalStats * -pgstat_fetch_stat_wal(void) -{ - backend_read_statsfile(); - - return &walStats; -} - -/* - * --------- - * pgstat_fetch_slru() - - * - * Support function for the SQL-callable pgstat* functions. Returns - * a pointer to the slru statistics struct. - * --------- - */ -PgStat_SLRUStats * -pgstat_fetch_slru(void) -{ - backend_read_statsfile(); - - return slruStats; -} - -/* - * --------- - * pgstat_fetch_replslot() - - * - * Support function for the SQL-callable pgstat* functions. Returns - * a pointer to the replication slot statistics struct. - * --------- - */ -PgStat_StatReplSlotEntry * -pgstat_fetch_replslot(NameData slotname) -{ - backend_read_statsfile(); - - return pgstat_get_replslot_entry(slotname, false); -} - -/* - * Shut down a single backend's statistics reporting at process exit. - * - * Flush any remaining statistics counts out to the collector. - * Without this, operations triggered during backend exit (such as - * temp table deletions) won't be counted. - */ -static void -pgstat_shutdown_hook(int code, Datum arg) -{ - /* - * If we got as far as discovering our own database ID, we can report what - * we did to the collector. Otherwise, we'd be sending an invalid - * database ID, so forget it. (This means that accesses to pg_database - * during failed backend starts might never get counted.) - */ - if (OidIsValid(MyDatabaseId)) - pgstat_report_stat(true); -} - -/* ---------- - * pgstat_initialize() - - * - * Initialize pgstats state, and set up our on-proc-exit hook. - * Called from InitPostgres and AuxiliaryProcessMain. - * - * NOTE: MyDatabaseId isn't set yet; so the shutdown hook has to be careful. - * ---------- - */ -void -pgstat_initialize(void) -{ - /* - * Initialize prevWalUsage with pgWalUsage so that pgstat_send_wal() can - * calculate how much pgWalUsage counters are increased by substracting - * prevWalUsage from pgWalUsage. - */ - prevWalUsage = pgWalUsage; - - /* Set up a process-exit hook to clean up */ - on_shmem_exit(pgstat_shutdown_hook, 0); -} - -/* ------------------------------------------------------------ - * Local support functions follow - * ------------------------------------------------------------ - */ - - -/* ---------- - * pgstat_setheader() - - * - * Set common header fields in a statistics message - * ---------- - */ -static void -pgstat_setheader(PgStat_MsgHdr *hdr, StatMsgType mtype) -{ - hdr->m_type = mtype; -} - - -/* ---------- - * pgstat_send() - - * - * Send out one statistics message to the collector - * ---------- - */ -static void -pgstat_send(void *msg, int len) -{ - int rc; - - if (pgStatSock == PGINVALID_SOCKET) - return; - - ((PgStat_MsgHdr *) msg)->m_size = len; - - /* We'll retry after EINTR, but ignore all other failures */ - do - { - rc = send(pgStatSock, msg, len, 0); - } while (rc < 0 && errno == EINTR); - -#ifdef USE_ASSERT_CHECKING - /* In debug builds, log send failures ... */ - if (rc < 0) - elog(LOG, "could not send to statistics collector: %m"); -#endif -} - -/* - * Report the timestamp of transaction start queueing on the resource group. - */ -void -pgstat_report_resgroup(Oid groupid) -{ - volatile PgBackendStatus *beentry = MyBEEntry; - - if (!beentry) - return; - - /* - * Update my status entry, following the protocol of bumping - * st_changecount before and after. We use a volatile pointer here to - * ensure the compiler doesn't try to get cute. - */ - beentry->st_changecount++; - - beentry->st_rsgid = groupid; - beentry->st_changecount++; - Assert((beentry->st_changecount & 1) == 0); -} - -/* ---------- - * pgstat_report_sessionid() - - * - * Called from cdbgang to report a session is reset. - * - * ---------- - */ -void -pgstat_report_sessionid(int new_sessionid) -{ - volatile PgBackendStatus *beentry = MyBEEntry; - - if (!beentry) - return; - - beentry->st_changecount++; - beentry->st_session_id = new_sessionid; - beentry->st_changecount++; - Assert((beentry->st_changecount & 1) == 0); -} - -/* ---------- - * pgstat_send_archiver() - - * - * Tell the collector about the WAL file that we successfully - * archived or failed to archive. - * ---------- - */ -void -pgstat_send_archiver(const char *xlog, bool failed) -{ - PgStat_MsgArchiver msg; - - /* - * Prepare and send the message - */ - pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_ARCHIVER); - msg.m_failed = failed; - strlcpy(msg.m_xlog, xlog, sizeof(msg.m_xlog)); - msg.m_timestamp = GetCurrentTimestamp(); - pgstat_send(&msg, sizeof(msg)); -} - -/* ---------- - * pgstat_send_bgwriter() - - * - * Send bgwriter statistics to the collector - * ---------- - */ -void -pgstat_send_bgwriter(void) -{ - /* We assume this initializes to zeroes */ - static const PgStat_MsgBgWriter all_zeroes; - - /* - * Non hot standby mirror should not send bgwriter statistics to the - * stat collector, since stat collector is not started when mirror - * is not in hot standby mode. Sending statistics would cause the - * Recv-Q buffer to be filled up. - */ - if (!EnableHotStandby && IsRoleMirror()) - return; - - /* - * This function can be called even if nothing at all has happened. In - * this case, avoid sending a completely empty message to the stats - * collector. - */ - if (memcmp(&BgWriterStats, &all_zeroes, sizeof(PgStat_MsgBgWriter)) == 0) - return; - - /* - * Prepare and send the message - */ - pgstat_setheader(&BgWriterStats.m_hdr, PGSTAT_MTYPE_BGWRITER); - pgstat_send(&BgWriterStats, sizeof(BgWriterStats)); - - /* - * Clear out the statistics buffer, so it can be re-used. - */ - MemSet(&BgWriterStats, 0, sizeof(BgWriterStats)); -} - -/* - * pgstat_send_qd_tabstats() - - * - * Send the writer QE's tables' pgstat for current nest xact level - * to QD through libpq at each end of a statement. - * - * For a single statement executed on the writer QE, it wouldn't operate - * too many tables, so the effort should be small. - * - * We used don't have accurate table stat on QD, especially for partition - * tables since these table stats counters are counted through the access - * method on segments that contain data. - */ -void -pgstat_send_qd_tabstats(void) -{ - int nest_level; - StringInfoData buf; - StringInfoData stat_data; - PgStat_TableXactStatus *trans; - - if (!pgstat_track_counts || !pgStatXactStack) - return; - - nest_level = GetCurrentTransactionNestLevel(); - if (nest_level != pgStatXactStack->nest_level) - return; - - trans = pgStatXactStack->first; - initStringInfo(&stat_data); - - for (; trans != NULL; trans = trans->next) - { - PgStatTabRecordFromQE record; - PgStat_TableStatus *tabstat = trans->parent; - GpPolicy *gppolicy = GpPolicyFetch(tabstat->t_id); - - switch (gppolicy->ptype) - { - case POLICYTYPE_ENTRY: - /* - * No need to send catalog table's pgstat to QD since if the catalog - * table get updated on QE, QD should have the same update. - */ - continue; - case POLICYTYPE_REPLICATED: - /* - * gppolicy->numsegments has the same value on all segments even when we are doing expand. - */ - if (GpIdentity.segindex != tabstat->t_id % gppolicy->numsegments) - continue; - break; - case POLICYTYPE_PARTITIONED: - break; - default: - elog(ERROR, "unrecognized policy type %d", gppolicy->ptype); - } - - record.table_stat.tuples_inserted = trans->tuples_inserted; - record.table_stat.tuples_updated = trans->tuples_updated; - record.table_stat.tuples_deleted = trans->tuples_deleted; - record.table_stat.inserted_pre_trunc = trans->inserted_pre_trunc; - record.table_stat.updated_pre_trunc = trans->updated_pre_trunc; - record.table_stat.deleted_pre_trunc = trans->deleted_pre_trunc; - record.table_stat.t_id = tabstat->t_id; - record.table_stat.t_shared = tabstat->t_shared; - record.table_stat.t_truncated = trans->truncated; - record.nest_level = trans->nest_level; - - appendBinaryStringInfo( - &stat_data, (char *)&record, sizeof(PgStatTabRecordFromQE)); - ereport(DEBUG3, - (errmsg("Send pgstat for current xact nest_level: %d, rel oid: %d. " - "Inserted: %ld, updated: %ld, deleted: %ld.", - nest_level, tabstat->t_id, - trans->tuples_inserted, trans->tuples_updated, - trans->tuples_deleted))); - } - - if (stat_data.len > 0) - { - pq_beginmessage(&buf, 'y'); - pq_sendstring(&buf, "PGSTAT"); - - /* - * Don't mark the pgresult PGASYNC_READY when receive this message on QD. - * Otherwise, QD may think the result is complete and start to process it. - * But actually there may still have messages not received yet on QD belong - * to same pgresult. - */ - pq_sendbyte(&buf, false); - - pq_sendint(&buf, PGExtraTypeTableStats, sizeof(PGExtraType)); - pq_sendint(&buf, stat_data.len, sizeof(int)); - pq_sendbytes(&buf, stat_data.data, stat_data.len); - pq_endmessage(&buf); - } -} - -/* - * pgstat_combine_one_qe_result() - - * - * Combine one pg_result's pgstat tables' stats from a QE. Process pg_result - * contains stats send from QE. - * The function should be called on QD after get dispatch results from QE - * for the operations that could have tuple inserted/updated/deleted on - * QEs. - * Normally using pgstat_combine_from_qe(). Current function are also called - * in cdbCopyEndInternal(). - * oidMap - an oid bitmapset, record the processed table oid. To distinguish - * whether reset or sum on current PgStat_TableXactStatus entry for the table. - * pgresult - pointer of pg_result - * nest_level - current xact nest level - * segindex - the QE segment index for the current pgresult, for logging purpose - */ -void -pgstat_combine_one_qe_result(List **oidList, struct pg_result *pgresult, - int nest_level, int32 segindex) -{ - int arrayLen; - PgStatTabRecordFromQE *records; - PgStat_SubXactStatus *xact_state; - PgStat_TableStatus *pgstat_info; - PgStat_TableXactStatus *trans; - - if (!pgresult || pgresult->extraslen < 1 || pgresult->extraType != PGExtraTypeTableStats) - return; - /* - * If this is the first rel to be modified at the current nest level, - * we first have to push a transaction stack entry. - */ - xact_state = get_tabstat_stack_level(nest_level); - - arrayLen = pgresult->extraslen / sizeof(PgStatTabRecordFromQE); - records = (PgStatTabRecordFromQE *) pgresult->extras; - for (int i = 0; i < arrayLen; i++) - { - char *relname; - Assert(records[i].nest_level = nest_level); - - relname = get_rel_name(records[i].table_stat.t_id); - if (!relname) - continue; - - /* Find or create a tabstat entry for the rel */ - pgstat_info = get_tabstat_entry( - records[i].table_stat.t_id, records[i].table_stat.t_shared); - - if (pgstat_info->trans == NULL || - pgstat_info->trans->nest_level != nest_level) - add_tabstat_xact_level(pgstat_info, nest_level); - trans = pgstat_info->trans; - if (list_member_oid(*oidList, records[i].table_stat.t_id)) - { - /* - * Same table pgstat from different QE; - */ - trans->tuples_inserted += records[i].table_stat.tuples_inserted; - trans->tuples_updated += records[i].table_stat.tuples_updated; - trans->tuples_deleted += records[i].table_stat.tuples_deleted; - trans->truncated = (trans->truncated || - records[i].table_stat.t_truncated) ? true : false; - trans->inserted_pre_trunc += records[i].table_stat.inserted_pre_trunc; - trans->updated_pre_trunc += records[i].table_stat.updated_pre_trunc; - trans->deleted_pre_trunc += records[i].table_stat.deleted_pre_trunc; - } - else - { - /* - * First time see the table from a QE, overwrite existing records, - * since the results could belong to same transaction nest level, - * it already contians the previous count collected from previous - * statement. - */ - *oidList = lappend_oid(*oidList, records[i].table_stat.t_id); - trans->tuples_inserted = records[i].table_stat.tuples_inserted; - trans->tuples_updated = records[i].table_stat.tuples_updated; - trans->tuples_deleted = records[i].table_stat.tuples_deleted; - trans->truncated = records[i].table_stat.t_truncated; - trans->inserted_pre_trunc = records[i].table_stat.inserted_pre_trunc; - trans->updated_pre_trunc = records[i].table_stat.updated_pre_trunc; - trans->deleted_pre_trunc = records[i].table_stat.deleted_pre_trunc; - -#ifdef FAULT_INJECTOR - FaultInjector_InjectFaultIfSet( - "gp_pgstat_report_on_master", DDLNotSpecified, - "", relname); -#endif - } - - ereport(DEBUG3, - (errmsg("Update pgstat from segment %d for current xact nest_level: %d, " - "relation name: %s, relation oid: %d. " - "Sum of inserted: %ld, updated: %ld, deleted: %ld.", - segindex, nest_level, relname, pgstat_info->t_id, - trans->tuples_inserted, trans->tuples_updated, - trans->tuples_deleted))); - pfree(relname); - } -} - -/* - * pgstat_combine_from_qe() - - * - * Combine the pgstat tables stats on QD from dispatch result for each QE. - * The function should be called on QD after get dispatch results from QE - * for the operations that could have tuple inserted/updated/deleted on - * QEs. - * Currently this function are called in cdbdisp_dispatchCommandInternal(), - * mppExecutorFinishup() and ExecSetParamPlan(). - */ -void -pgstat_combine_from_qe(CdbDispatchResults *results, int writerSliceIndex) -{ - CdbDispatchResult *dispatchResult; - CdbDispatchResult *resultEnd; - struct pg_result *pgresult; - List *oidList = NIL; - int nest_level; - - if (!pgstat_track_counts) - return; - - resultEnd = cdbdisp_resultEnd(results, writerSliceIndex); - nest_level = GetCurrentTransactionNestLevel(); - - for (dispatchResult = cdbdisp_resultBegin(results, writerSliceIndex); - dispatchResult < resultEnd; ++dispatchResult) - { - pgresult = cdbdisp_getPGresult(dispatchResult, dispatchResult->okindex); - if (pgresult && !dispatchResult->errcode && pgresult->extraslen > 0 && - pgresult->extraType == PGExtraTypeTableStats) - { - pgstat_combine_one_qe_result(&oidList, pgresult, nest_level, - dispatchResult->segdbDesc->segindex); - } - } -} -/* ---------- - * pgstat_send_wal() - - * - * Send WAL statistics to the collector. - * - * If 'force' is not set, WAL stats message is only sent if enough time has - * passed since last one was sent to reach PGSTAT_STAT_INTERVAL. - * ---------- - */ -void -pgstat_send_wal(bool force) -{ - static TimestampTz sendTime = 0; - - /* - * This function can be called even if nothing at all has happened. In - * this case, avoid sending a completely empty message to the stats - * collector. - * - * Check wal_records counter to determine whether any WAL activity has - * happened since last time. Note that other WalUsage counters don't need - * to be checked because they are incremented always together with - * wal_records counter. - * - * m_wal_buffers_full also doesn't need to be checked because it's - * incremented only when at least one WAL record is generated (i.e., - * wal_records counter is incremented). But for safely, we assert that - * m_wal_buffers_full is always zero when no WAL record is generated - * - * This function can be called by a process like walwriter that normally - * generates no WAL records. To determine whether any WAL activity has - * happened at that process since the last time, the numbers of WAL writes - * and syncs are also checked. - */ - if (pgWalUsage.wal_records == prevWalUsage.wal_records && - WalStats.m_wal_write == 0 && WalStats.m_wal_sync == 0) - { - Assert(WalStats.m_wal_buffers_full == 0); - return; - } - - if (!force) - { - TimestampTz now = GetCurrentTimestamp(); - - /* - * Don't send a message unless it's been at least PGSTAT_STAT_INTERVAL - * msec since we last sent one to avoid overloading the stats - * collector. - */ - if (!TimestampDifferenceExceeds(sendTime, now, PGSTAT_STAT_INTERVAL)) - return; - sendTime = now; - } - - /* - * Set the counters related to generated WAL data if the counters were - * updated. - */ - if (pgWalUsage.wal_records != prevWalUsage.wal_records) - { - WalUsage walusage; - - /* - * Calculate how much WAL usage counters were increased by - * substracting the previous counters from the current ones. Fill the - * results in WAL stats message. - */ - MemSet(&walusage, 0, sizeof(WalUsage)); - WalUsageAccumDiff(&walusage, &pgWalUsage, &prevWalUsage); - - WalStats.m_wal_records = walusage.wal_records; - WalStats.m_wal_fpi = walusage.wal_fpi; - WalStats.m_wal_bytes = walusage.wal_bytes; - - /* - * Save the current counters for the subsequent calculation of WAL - * usage. - */ - prevWalUsage = pgWalUsage; - } - - /* - * Prepare and send the message - */ - pgstat_setheader(&WalStats.m_hdr, PGSTAT_MTYPE_WAL); - pgstat_send(&WalStats, sizeof(WalStats)); - - /* - * Clear out the statistics buffer, so it can be re-used. - */ - MemSet(&WalStats, 0, sizeof(WalStats)); -} - -/* ---------- - * pgstat_send_slru() - - * - * Send SLRU statistics to the collector - * ---------- - */ -static void -pgstat_send_slru(void) -{ - /* We assume this initializes to zeroes */ - static const PgStat_MsgSLRU all_zeroes; - - for (int i = 0; i < SLRU_NUM_ELEMENTS; i++) - { - /* - * This function can be called even if nothing at all has happened. In - * this case, avoid sending a completely empty message to the stats - * collector. - */ - if (memcmp(&SLRUStats[i], &all_zeroes, sizeof(PgStat_MsgSLRU)) == 0) - continue; - - /* set the SLRU type before each send */ - SLRUStats[i].m_index = i; - - /* - * Prepare and send the message - */ - pgstat_setheader(&SLRUStats[i].m_hdr, PGSTAT_MTYPE_SLRU); - pgstat_send(&SLRUStats[i], sizeof(PgStat_MsgSLRU)); - - /* - * Clear out the statistics buffer, so it can be re-used. - */ - MemSet(&SLRUStats[i], 0, sizeof(PgStat_MsgSLRU)); - } -} - - -/* ---------- - * PgstatCollectorMain() - - * - * Start up the statistics collector process. This is the body of the - * postmaster child process. - * - * The argc/argv parameters are valid only in EXEC_BACKEND case. - * ---------- - */ -NON_EXEC_STATIC void -PgstatCollectorMain(int argc, char *argv[]) -{ - int len; - PgStat_Msg msg; - int wr; - WaitEvent event; - WaitEventSet *wes; - - /* - * Ignore all signals usually bound to some action in the postmaster, - * except SIGHUP and SIGQUIT. Note we don't need a SIGUSR1 handler to - * support latch operations, because we only use a local latch. - */ - pqsignal(SIGHUP, SignalHandlerForConfigReload); - pqsignal(SIGINT, SIG_IGN); - pqsignal(SIGTERM, SIG_IGN); - pqsignal(SIGQUIT, SignalHandlerForShutdownRequest); - pqsignal(SIGALRM, SIG_IGN); - pqsignal(SIGPIPE, SIG_IGN); - pqsignal(SIGUSR1, SIG_IGN); - pqsignal(SIGUSR2, SIG_IGN); - /* Reset some signals that are accepted by postmaster but not here */ - pqsignal(SIGCHLD, SIG_DFL); - PG_SETMASK(&UnBlockSig); - - MyBackendType = B_STATS_COLLECTOR; - init_ps_display(NULL); - - /* - * Read in existing stats files or initialize the stats to zero. - */ - pgStatRunningInCollector = true; - pgStatDBHash = pgstat_read_statsfiles(InvalidOid, true, true); - - /* Prepare to wait for our latch or data in our socket. */ - wes = CreateWaitEventSet(CurrentMemoryContext, 3); - AddWaitEventToSet(wes, WL_LATCH_SET, PGINVALID_SOCKET, MyLatch, NULL); - AddWaitEventToSet(wes, WL_POSTMASTER_DEATH, PGINVALID_SOCKET, NULL, NULL); - AddWaitEventToSet(wes, WL_SOCKET_READABLE, pgStatSock, NULL, NULL); - - /* - * Loop to process messages until we get SIGQUIT or detect ungraceful - * death of our parent postmaster. - * - * For performance reasons, we don't want to do ResetLatch/WaitLatch after - * every message; instead, do that only after a recv() fails to obtain a - * message. (This effectively means that if backends are sending us stuff - * like mad, we won't notice postmaster death until things slack off a - * bit; which seems fine.) To do that, we have an inner loop that - * iterates as long as recv() succeeds. We do check ConfigReloadPending - * inside the inner loop, which means that such interrupts will get - * serviced but the latch won't get cleared until next time there is a - * break in the action. - */ - for (;;) - { - /* Clear any already-pending wakeups */ - ResetLatch(MyLatch); - - /* - * Quit if we get SIGQUIT from the postmaster. - */ - if (ShutdownRequestPending) - break; - - /* - * Inner loop iterates as long as we keep getting messages, or until - * ShutdownRequestPending becomes set. - */ - while (!ShutdownRequestPending) - { - /* - * Reload configuration if we got SIGHUP from the postmaster. - */ - if (ConfigReloadPending) - { - ConfigReloadPending = false; - ProcessConfigFile(PGC_SIGHUP); - } - - /* - * Write the stats file(s) if a new request has arrived that is - * not satisfied by existing file(s). - */ - if (pgstat_write_statsfile_needed()) - pgstat_write_statsfiles(false, false); - - /* - * Try to receive and process a message. This will not block, - * since the socket is set to non-blocking mode. - * - * XXX On Windows, we have to force pgwin32_recv to cooperate, - * despite the previous use of pg_set_noblock() on the socket. - * This is extremely broken and should be fixed someday. - */ -#ifdef WIN32 - pgwin32_noblock = 1; -#endif - - len = recv(pgStatSock, (char *) &msg, - sizeof(PgStat_Msg), 0); - -#ifdef WIN32 - pgwin32_noblock = 0; -#endif - - if (len < 0) - { - if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) - break; /* out of inner loop */ - ereport(ERROR, - (errcode_for_socket_access(), - errmsg("could not read statistics message: %m"))); - } - - /* - * We ignore messages that are smaller than our common header - */ - if (len < sizeof(PgStat_MsgHdr)) - continue; - - /* - * The received length must match the length in the header - */ - if (msg.msg_hdr.m_size != len) - continue; - - /* - * O.K. - we accept this message. Process it. - */ - switch (msg.msg_hdr.m_type) - { - case PGSTAT_MTYPE_DUMMY: - break; - - case PGSTAT_MTYPE_INQUIRY: - pgstat_recv_inquiry(&msg.msg_inquiry, len); - break; - - case PGSTAT_MTYPE_TABSTAT: - pgstat_recv_tabstat(&msg.msg_tabstat, len); - break; - - case PGSTAT_MTYPE_TABPURGE: - pgstat_recv_tabpurge(&msg.msg_tabpurge, len); - break; - - case PGSTAT_MTYPE_DROPDB: - pgstat_recv_dropdb(&msg.msg_dropdb, len); - break; - - case PGSTAT_MTYPE_RESETCOUNTER: - pgstat_recv_resetcounter(&msg.msg_resetcounter, len); - break; - - case PGSTAT_MTYPE_RESETSHAREDCOUNTER: - pgstat_recv_resetsharedcounter(&msg.msg_resetsharedcounter, - len); - break; - - case PGSTAT_MTYPE_RESETSINGLECOUNTER: - pgstat_recv_resetsinglecounter(&msg.msg_resetsinglecounter, - len); - break; - - case PGSTAT_MTYPE_RESETSLRUCOUNTER: - pgstat_recv_resetslrucounter(&msg.msg_resetslrucounter, - len); - break; - - case PGSTAT_MTYPE_RESETREPLSLOTCOUNTER: - pgstat_recv_resetreplslotcounter(&msg.msg_resetreplslotcounter, - len); - break; - - case PGSTAT_MTYPE_AUTOVAC_START: - pgstat_recv_autovac(&msg.msg_autovacuum_start, len); - break; - - case PGSTAT_MTYPE_VACUUM: - pgstat_recv_vacuum(&msg.msg_vacuum, len); - break; - - case PGSTAT_MTYPE_ANALYZE: - pgstat_recv_analyze(&msg.msg_analyze, len); - break; - - case PGSTAT_MTYPE_ARCHIVER: - pgstat_recv_archiver(&msg.msg_archiver, len); - break; - - case PGSTAT_MTYPE_BGWRITER: - pgstat_recv_bgwriter(&msg.msg_bgwriter, len); - break; - - case PGSTAT_MTYPE_QUEUESTAT: /* GPDB */ - pgstat_recv_queuestat((PgStat_MsgQueuestat *) &msg, len); - break; - - case PGSTAT_MTYPE_WAL: - pgstat_recv_wal(&msg.msg_wal, len); - break; - - case PGSTAT_MTYPE_SLRU: - pgstat_recv_slru(&msg.msg_slru, len); - break; - - case PGSTAT_MTYPE_FUNCSTAT: - pgstat_recv_funcstat(&msg.msg_funcstat, len); - break; - - case PGSTAT_MTYPE_FUNCPURGE: - pgstat_recv_funcpurge(&msg.msg_funcpurge, len); - break; - - case PGSTAT_MTYPE_RECOVERYCONFLICT: - pgstat_recv_recoveryconflict(&msg.msg_recoveryconflict, - len); - break; - - case PGSTAT_MTYPE_DEADLOCK: - pgstat_recv_deadlock(&msg.msg_deadlock, len); - break; - - case PGSTAT_MTYPE_TEMPFILE: - pgstat_recv_tempfile(&msg.msg_tempfile, len); - break; - - case PGSTAT_MTYPE_CHECKSUMFAILURE: - pgstat_recv_checksum_failure(&msg.msg_checksumfailure, - len); - break; - - case PGSTAT_MTYPE_REPLSLOT: - pgstat_recv_replslot(&msg.msg_replslot, len); - break; - - case PGSTAT_MTYPE_CONNECT: - pgstat_recv_connect(&msg.msg_connect, len); - break; - - case PGSTAT_MTYPE_DISCONNECT: - pgstat_recv_disconnect(&msg.msg_disconnect, len); - break; - - default: - break; - } - } /* end of inner message-processing loop */ - - /* Sleep until there's something to do */ -#ifndef WIN32 - wr = WaitEventSetWait(wes, -1L, &event, 1, WAIT_EVENT_PGSTAT_MAIN); -#else - - /* - * Windows, at least in its Windows Server 2003 R2 incarnation, - * sometimes loses FD_READ events. Waking up and retrying the recv() - * fixes that, so don't sleep indefinitely. This is a crock of the - * first water, but until somebody wants to debug exactly what's - * happening there, this is the best we can do. The two-second - * timeout matches our pre-9.2 behavior, and needs to be short enough - * to not provoke "using stale statistics" complaints from - * backend_read_statsfile. - */ - wr = WaitEventSetWait(wes, 2 * 1000L /* msec */ , &event, 1, - WAIT_EVENT_PGSTAT_MAIN); -#endif - - /* - * Emergency bailout if postmaster has died. This is to avoid the - * necessity for manual cleanup of all postmaster children. - */ - if (wr == 1 && event.events == WL_POSTMASTER_DEATH) - break; - } /* end of outer loop */ - - /* - * Save the final stats to reuse at next startup. - */ - pgstat_write_statsfiles(true, true); - - FreeWaitEventSet(wes); - - exit(0); -} - -/* - * Subroutine to clear stats in a database entry - * - * Tables and functions hashes are initialized to empty. - */ -static void -reset_dbentry_counters(PgStat_StatDBEntry *dbentry) -{ - HASHCTL hash_ctl; - - dbentry->n_xact_commit = 0; - dbentry->n_xact_rollback = 0; - dbentry->n_blocks_fetched = 0; - dbentry->n_blocks_hit = 0; - dbentry->n_tuples_returned = 0; - dbentry->n_tuples_fetched = 0; - dbentry->n_tuples_inserted = 0; - dbentry->n_tuples_updated = 0; - dbentry->n_tuples_deleted = 0; - dbentry->last_autovac_time = 0; - dbentry->n_conflict_tablespace = 0; - dbentry->n_conflict_lock = 0; - dbentry->n_conflict_snapshot = 0; - dbentry->n_conflict_bufferpin = 0; - dbentry->n_conflict_startup_deadlock = 0; - dbentry->n_temp_files = 0; - dbentry->n_temp_bytes = 0; - dbentry->n_deadlocks = 0; - dbentry->n_checksum_failures = 0; - dbentry->last_checksum_failure = 0; - dbentry->n_block_read_time = 0; - dbentry->n_block_write_time = 0; - dbentry->n_sessions = 0; - dbentry->total_session_time = 0; - dbentry->total_active_time = 0; - dbentry->total_idle_in_xact_time = 0; - dbentry->n_sessions_abandoned = 0; - dbentry->n_sessions_fatal = 0; - dbentry->n_sessions_killed = 0; - - dbentry->stat_reset_timestamp = GetCurrentTimestamp(); - dbentry->stats_timestamp = 0; - - hash_ctl.keysize = sizeof(Oid); - hash_ctl.entrysize = sizeof(PgStat_StatTabEntry); - dbentry->tables = hash_create("Per-database table", - PGSTAT_TAB_HASH_SIZE, - &hash_ctl, - HASH_ELEM | HASH_BLOBS); - - hash_ctl.keysize = sizeof(Oid); - hash_ctl.entrysize = sizeof(PgStat_StatFuncEntry); - dbentry->functions = hash_create("Per-database function", - PGSTAT_FUNCTION_HASH_SIZE, - &hash_ctl, - HASH_ELEM | HASH_BLOBS); -} - -/* - * Lookup the hash table entry for the specified database. If no hash - * table entry exists, initialize it, if the create parameter is true. - * Else, return NULL. - */ -static PgStat_StatDBEntry * -pgstat_get_db_entry(Oid databaseid, bool create) -{ - PgStat_StatDBEntry *result; - bool found; - HASHACTION action = (create ? HASH_ENTER : HASH_FIND); - - /* Lookup or create the hash table entry for this database */ - result = (PgStat_StatDBEntry *) hash_search(pgStatDBHash, - &databaseid, - action, &found); - - if (!create && !found) - return NULL; - - /* - * If not found, initialize the new one. This creates empty hash tables - * for tables and functions, too. - */ - if (!found) - reset_dbentry_counters(result); - - return result; -} - - -/* - * Lookup the hash table entry for the specified table. If no hash - * table entry exists, initialize it, if the create parameter is true. - * Else, return NULL. - */ -static PgStat_StatTabEntry * -pgstat_get_tab_entry(PgStat_StatDBEntry *dbentry, Oid tableoid, bool create) -{ - PgStat_StatTabEntry *result; - bool found; - HASHACTION action = (create ? HASH_ENTER : HASH_FIND); - - /* Lookup or create the hash table entry for this table */ - result = (PgStat_StatTabEntry *) hash_search(dbentry->tables, - &tableoid, - action, &found); - - if (!create && !found) - return NULL; - - /* If not found, initialize the new one. */ - if (!found) - { - result->numscans = 0; - result->tuples_returned = 0; - result->tuples_fetched = 0; - result->tuples_inserted = 0; - result->tuples_updated = 0; - result->tuples_deleted = 0; - result->tuples_hot_updated = 0; - result->n_live_tuples = 0; - result->n_dead_tuples = 0; - result->changes_since_analyze = 0; - result->inserts_since_vacuum = 0; - result->blocks_fetched = 0; - result->blocks_hit = 0; - result->vacuum_timestamp = 0; - result->vacuum_count = 0; - result->autovac_vacuum_timestamp = 0; - result->autovac_vacuum_count = 0; - result->analyze_timestamp = 0; - result->analyze_count = 0; - result->autovac_analyze_timestamp = 0; - result->autovac_analyze_count = 0; - } - - return result; -} - - -/* ---------- - * pgstat_write_statsfiles() - - * Write the global statistics file, as well as requested DB files. - * - * 'permanent' specifies writing to the permanent files not temporary ones. - * When true (happens only when the collector is shutting down), also remove - * the temporary files so that backends starting up under a new postmaster - * can't read old data before the new collector is ready. - * - * When 'allDbs' is false, only the requested databases (listed in - * pending_write_requests) will be written; otherwise, all databases - * will be written. - * ---------- - */ -static void -pgstat_write_statsfiles(bool permanent, bool allDbs) -{ - HASH_SEQ_STATUS hstat; - HASH_SEQ_STATUS qstat; - PgStat_StatDBEntry *dbentry; - PgStat_StatQueueEntry *queueentry; - FILE *fpout; - int32 format_id; - const char *tmpfile = permanent ? PGSTAT_STAT_PERMANENT_TMPFILE : pgstat_stat_tmpname; - const char *statfile = permanent ? PGSTAT_STAT_PERMANENT_FILENAME : pgstat_stat_filename; - int rc; - - elog(DEBUG2, "writing stats file \"%s\"", statfile); - - /* - * Open the statistics temp file to write out the current values. - */ - fpout = AllocateFile(tmpfile, PG_BINARY_W); - if (fpout == NULL) - { - ereport(LOG, - (errcode_for_file_access(), - errmsg("could not open temporary statistics file \"%s\": %m", - tmpfile))); - return; - } - - /* - * Set the timestamp of the stats file. - */ - globalStats.stats_timestamp = GetCurrentTimestamp(); - - /* - * Write the file header --- currently just a format ID. - */ - format_id = PGSTAT_FILE_FORMAT_ID; - rc = fwrite(&format_id, sizeof(format_id), 1, fpout); - (void) rc; /* we'll check for error with ferror */ - - /* - * Write global stats struct - */ - rc = fwrite(&globalStats, sizeof(globalStats), 1, fpout); - (void) rc; /* we'll check for error with ferror */ - - /* - * Write archiver stats struct - */ - rc = fwrite(&archiverStats, sizeof(archiverStats), 1, fpout); - (void) rc; /* we'll check for error with ferror */ - - /* - * Write WAL stats struct - */ - rc = fwrite(&walStats, sizeof(walStats), 1, fpout); - (void) rc; /* we'll check for error with ferror */ - - /* - * Write SLRU stats struct - */ - rc = fwrite(slruStats, sizeof(slruStats), 1, fpout); - (void) rc; /* we'll check for error with ferror */ - - /* - * Walk through the database table. - */ - hash_seq_init(&hstat, pgStatDBHash); - while ((dbentry = (PgStat_StatDBEntry *) hash_seq_search(&hstat)) != NULL) - { - /* - * Write out the table and function stats for this DB into the - * appropriate per-DB stat file, if required. - */ - if (allDbs || pgstat_db_requested(dbentry->databaseid)) - { - /* Make DB's timestamp consistent with the global stats */ - dbentry->stats_timestamp = globalStats.stats_timestamp; - - pgstat_write_db_statsfile(dbentry, permanent); - } - - /* - * Write out the DB entry. We don't write the tables or functions - * pointers, since they're of no use to any other process. - */ - fputc('D', fpout); - rc = fwrite(dbentry, offsetof(PgStat_StatDBEntry, tables), 1, fpout); - (void) rc; /* we'll check for error with ferror */ - } - - /* - * Walk through resource queue stats. - */ - hash_seq_init(&qstat, pgStatQueueHash); - while ((queueentry = (PgStat_StatQueueEntry *) hash_seq_search(&qstat)) != NULL) - { - fputc('Q', fpout); - fwrite(queueentry, sizeof(PgStat_StatQueueEntry), 1, fpout); - } - /* - * Write replication slot stats struct - */ - if (replSlotStatHash) - { - PgStat_StatReplSlotEntry *slotent; - - hash_seq_init(&hstat, replSlotStatHash); - while ((slotent = (PgStat_StatReplSlotEntry *) hash_seq_search(&hstat)) != NULL) - { - fputc('R', fpout); - rc = fwrite(slotent, sizeof(PgStat_StatReplSlotEntry), 1, fpout); - (void) rc; /* we'll check for error with ferror */ - } - } - - /* - * No more output to be done. Close the temp file and replace the old - * pgstat.stat with it. The ferror() check replaces testing for error - * after each individual fputc or fwrite above. - */ - fputc('E', fpout); - - if (ferror(fpout)) - { - ereport(LOG, - (errcode_for_file_access(), - errmsg("could not write temporary statistics file \"%s\": %m", - tmpfile))); - FreeFile(fpout); - unlink(tmpfile); - } - else if (FreeFile(fpout) < 0) - { - ereport(LOG, - (errcode_for_file_access(), - errmsg("could not close temporary statistics file \"%s\": %m", - tmpfile))); - unlink(tmpfile); - } - else if (rename(tmpfile, statfile) < 0) - { - ereport(LOG, - (errcode_for_file_access(), - errmsg("could not rename temporary statistics file \"%s\" to \"%s\": %m", - tmpfile, statfile))); - unlink(tmpfile); - } - - if (permanent) - unlink(pgstat_stat_filename); - - /* - * Now throw away the list of requests. Note that requests sent after we - * started the write are still waiting on the network socket. - */ - list_free(pending_write_requests); - pending_write_requests = NIL; -} - -/* - * return the filename for a DB stat file; filename is the output buffer, - * of length len. - */ -static void -get_dbstat_filename(bool permanent, bool tempname, Oid databaseid, - char *filename, int len) -{ - int printed; - - /* NB -- pgstat_reset_remove_files knows about the pattern this uses */ - printed = snprintf(filename, len, "%s/db_%u.%s", - permanent ? PGSTAT_STAT_PERMANENT_DIRECTORY : - pgstat_stat_directory, - databaseid, - tempname ? "tmp" : "stat"); - if (printed >= len) - elog(ERROR, "overlength pgstat path"); -} - -/* ---------- - * pgstat_write_db_statsfile() - - * Write the stat file for a single database. - * - * If writing to the permanent file (happens when the collector is - * shutting down only), remove the temporary file so that backends - * starting up under a new postmaster can't read the old data before - * the new collector is ready. - * ---------- - */ -static void -pgstat_write_db_statsfile(PgStat_StatDBEntry *dbentry, bool permanent) -{ - HASH_SEQ_STATUS tstat; - HASH_SEQ_STATUS fstat; - PgStat_StatTabEntry *tabentry; - PgStat_StatFuncEntry *funcentry; - FILE *fpout; - int32 format_id; - Oid dbid = dbentry->databaseid; - int rc; - char tmpfile[MAXPGPATH]; - char statfile[MAXPGPATH]; - - get_dbstat_filename(permanent, true, dbid, tmpfile, MAXPGPATH); - get_dbstat_filename(permanent, false, dbid, statfile, MAXPGPATH); - - elog(DEBUG2, "writing stats file \"%s\"", statfile); - - /* - * Open the statistics temp file to write out the current values. - */ - fpout = AllocateFile(tmpfile, PG_BINARY_W); - if (fpout == NULL) - { - ereport(LOG, - (errcode_for_file_access(), - errmsg("could not open temporary statistics file \"%s\": %m", - tmpfile))); - return; - } - - /* - * Write the file header --- currently just a format ID. - */ - format_id = PGSTAT_FILE_FORMAT_ID; - rc = fwrite(&format_id, sizeof(format_id), 1, fpout); - (void) rc; /* we'll check for error with ferror */ - - /* - * Walk through the database's access stats per table. - */ - hash_seq_init(&tstat, dbentry->tables); - while ((tabentry = (PgStat_StatTabEntry *) hash_seq_search(&tstat)) != NULL) - { - fputc('T', fpout); - rc = fwrite(tabentry, sizeof(PgStat_StatTabEntry), 1, fpout); - (void) rc; /* we'll check for error with ferror */ - } - - /* - * Walk through the database's function stats table. - */ - hash_seq_init(&fstat, dbentry->functions); - while ((funcentry = (PgStat_StatFuncEntry *) hash_seq_search(&fstat)) != NULL) - { - fputc('F', fpout); - rc = fwrite(funcentry, sizeof(PgStat_StatFuncEntry), 1, fpout); - (void) rc; /* we'll check for error with ferror */ - } - - /* - * No more output to be done. Close the temp file and replace the old - * pgstat.stat with it. The ferror() check replaces testing for error - * after each individual fputc or fwrite above. - */ - fputc('E', fpout); - - if (ferror(fpout)) - { - ereport(LOG, - (errcode_for_file_access(), - errmsg("could not write temporary statistics file \"%s\": %m", - tmpfile))); - FreeFile(fpout); - unlink(tmpfile); - } - else if (FreeFile(fpout) < 0) - { - ereport(LOG, - (errcode_for_file_access(), - errmsg("could not close temporary statistics file \"%s\": %m", - tmpfile))); - unlink(tmpfile); - } - else if (rename(tmpfile, statfile) < 0) - { - ereport(LOG, - (errcode_for_file_access(), - errmsg("could not rename temporary statistics file \"%s\" to \"%s\": %m", - tmpfile, statfile))); - unlink(tmpfile); - } - - if (permanent) - { - get_dbstat_filename(false, false, dbid, statfile, MAXPGPATH); - - elog(DEBUG2, "removing temporary stats file \"%s\"", statfile); - unlink(statfile); - } -} - -/* ---------- - * pgstat_read_statsfiles() - - * - * Reads in some existing statistics collector files and returns the - * databases hash table that is the top level of the data. - * - * If 'onlydb' is not InvalidOid, it means we only want data for that DB - * plus the shared catalogs ("DB 0"). We'll still populate the DB hash - * table for all databases, but we don't bother even creating table/function - * hash tables for other databases. - * - * 'permanent' specifies reading from the permanent files not temporary ones. - * When true (happens only when the collector is starting up), remove the - * files after reading; the in-memory status is now authoritative, and the - * files would be out of date in case somebody else reads them. - * - * If a 'deep' read is requested, table/function stats are read, otherwise - * the table/function hash tables remain empty. - * ---------- - */ -static HTAB * -pgstat_read_statsfiles(Oid onlydb, bool permanent, bool deep) -{ - PgStat_StatDBEntry *dbentry; - PgStat_StatDBEntry dbbuf; - HASHCTL hash_ctl; - HTAB *dbhash; - FILE *fpin; - int32 format_id; - bool found; - const char *statfile = permanent ? PGSTAT_STAT_PERMANENT_FILENAME : pgstat_stat_filename; - int i; - - PgStat_StatQueueEntry queuebuf; /* GPDB */ - PgStat_StatQueueEntry *queueentry; /* GPDB */ - HTAB *queuehash = NULL; /* GPDB */ - - /* - * The tables will live in pgStatLocalContext. - */ - pgstat_setup_memcxt(); - - /* - * Create the DB hashtable - */ - hash_ctl.keysize = sizeof(Oid); - hash_ctl.entrysize = sizeof(PgStat_StatDBEntry); - hash_ctl.hcxt = pgStatLocalContext; - dbhash = hash_create("Databases hash", PGSTAT_DB_HASH_SIZE, &hash_ctl, - HASH_ELEM | HASH_BLOBS | HASH_CONTEXT); - - /** - ** Create the Queue hashtable - **/ - memset(&hash_ctl, 0, sizeof(hash_ctl)); - hash_ctl.keysize = sizeof(Oid); - hash_ctl.entrysize = sizeof(PgStat_StatQueueEntry); - hash_ctl.hash = oid_hash; - hash_ctl.hcxt = pgStatLocalContext; - queuehash = hash_create("Queues hash", PGSTAT_QUEUE_HASH_SIZE, &hash_ctl, - HASH_ELEM | HASH_FUNCTION | HASH_CONTEXT); - pgStatQueueHash = queuehash; - - /* - * Clear out global, archiver, WAL and SLRU statistics so they start from - * zero in case we can't load an existing statsfile. - */ - memset(&globalStats, 0, sizeof(globalStats)); - memset(&archiverStats, 0, sizeof(archiverStats)); - memset(&walStats, 0, sizeof(walStats)); - memset(&slruStats, 0, sizeof(slruStats)); - - /* - * Set the current timestamp (will be kept only in case we can't load an - * existing statsfile). - */ - globalStats.stat_reset_timestamp = GetCurrentTimestamp(); - archiverStats.stat_reset_timestamp = globalStats.stat_reset_timestamp; - walStats.stat_reset_timestamp = globalStats.stat_reset_timestamp; - - /* - * Set the same reset timestamp for all SLRU items too. - */ - for (i = 0; i < SLRU_NUM_ELEMENTS; i++) - slruStats[i].stat_reset_timestamp = globalStats.stat_reset_timestamp; - - /* - * Try to open the stats file. If it doesn't exist, the backends simply - * return zero for anything and the collector simply starts from scratch - * with empty counters. - * - * ENOENT is a possibility if the stats collector is not running or has - * not yet written the stats file the first time. Any other failure - * condition is suspicious. - */ - if ((fpin = AllocateFile(statfile, PG_BINARY_R)) == NULL) - { - if (errno != ENOENT) - ereport(pgStatRunningInCollector ? LOG : WARNING, - (errcode_for_file_access(), - errmsg("could not open statistics file \"%s\": %m", - statfile))); - return dbhash; - } - - /* - * Verify it's of the expected format. - */ - if (fread(&format_id, 1, sizeof(format_id), fpin) != sizeof(format_id) || - format_id != PGSTAT_FILE_FORMAT_ID) - { - ereport(pgStatRunningInCollector ? LOG : WARNING, - (errmsg("corrupted statistics file \"%s\"", statfile))); - goto done; - } - - /* - * Read global stats struct - */ - if (fread(&globalStats, 1, sizeof(globalStats), fpin) != sizeof(globalStats)) - { - ereport(pgStatRunningInCollector ? LOG : WARNING, - (errmsg("corrupted statistics file \"%s\"", statfile))); - memset(&globalStats, 0, sizeof(globalStats)); - goto done; - } - - /* - * In the collector, disregard the timestamp we read from the permanent - * stats file; we should be willing to write a temp stats file immediately - * upon the first request from any backend. This only matters if the old - * file's timestamp is less than PGSTAT_STAT_INTERVAL ago, but that's not - * an unusual scenario. - */ - if (pgStatRunningInCollector) - globalStats.stats_timestamp = 0; - - /* - * Read archiver stats struct - */ - if (fread(&archiverStats, 1, sizeof(archiverStats), fpin) != sizeof(archiverStats)) - { - ereport(pgStatRunningInCollector ? LOG : WARNING, - (errmsg("corrupted statistics file \"%s\"", statfile))); - memset(&archiverStats, 0, sizeof(archiverStats)); - goto done; - } - - /* - * Read WAL stats struct - */ - if (fread(&walStats, 1, sizeof(walStats), fpin) != sizeof(walStats)) - { - ereport(pgStatRunningInCollector ? LOG : WARNING, - (errmsg("corrupted statistics file \"%s\"", statfile))); - memset(&walStats, 0, sizeof(walStats)); - goto done; - } - - /* - * Read SLRU stats struct - */ - if (fread(slruStats, 1, sizeof(slruStats), fpin) != sizeof(slruStats)) - { - ereport(pgStatRunningInCollector ? LOG : WARNING, - (errmsg("corrupted statistics file \"%s\"", statfile))); - memset(&slruStats, 0, sizeof(slruStats)); - goto done; - } - - /* - * We found an existing collector stats file. Read it and put all the - * hashtable entries into place. - */ - for (;;) - { - switch (fgetc(fpin)) - { - /* - * 'D' A PgStat_StatDBEntry struct describing a database - * follows. - */ - case 'D': - if (fread(&dbbuf, 1, offsetof(PgStat_StatDBEntry, tables), - fpin) != offsetof(PgStat_StatDBEntry, tables)) - { - ereport(pgStatRunningInCollector ? LOG : WARNING, - (errmsg("corrupted statistics file \"%s\"", - statfile))); - goto done; - } - - /* - * Add to the DB hash - */ - dbentry = (PgStat_StatDBEntry *) hash_search(dbhash, - (void *) &dbbuf.databaseid, - HASH_ENTER, - &found); - if (found) - { - ereport(pgStatRunningInCollector ? LOG : WARNING, - (errmsg("corrupted statistics file \"%s\"", - statfile))); - goto done; - } - - memcpy(dbentry, &dbbuf, sizeof(PgStat_StatDBEntry)); - dbentry->tables = NULL; - dbentry->functions = NULL; - - /* - * In the collector, disregard the timestamp we read from the - * permanent stats file; we should be willing to write a temp - * stats file immediately upon the first request from any - * backend. - */ - if (pgStatRunningInCollector) - dbentry->stats_timestamp = 0; - - /* - * Don't create tables/functions hashtables for uninteresting - * databases. - */ - if (onlydb != InvalidOid) - { - if (dbbuf.databaseid != onlydb && - dbbuf.databaseid != InvalidOid) - break; - } - - hash_ctl.keysize = sizeof(Oid); - hash_ctl.entrysize = sizeof(PgStat_StatTabEntry); - hash_ctl.hcxt = pgStatLocalContext; - dbentry->tables = hash_create("Per-database table", - PGSTAT_TAB_HASH_SIZE, - &hash_ctl, - HASH_ELEM | HASH_BLOBS | HASH_CONTEXT); - - memset(&hash_ctl, 0, sizeof(hash_ctl)); - hash_ctl.keysize = sizeof(Oid); - hash_ctl.entrysize = sizeof(PgStat_StatFuncEntry); - hash_ctl.hcxt = pgStatLocalContext; - dbentry->functions = hash_create("Per-database function", - PGSTAT_FUNCTION_HASH_SIZE, - &hash_ctl, - HASH_ELEM | HASH_BLOBS | HASH_CONTEXT); - - /* - * If requested, read the data from the database-specific - * file. Otherwise we just leave the hashtables empty. - */ - if (deep) - pgstat_read_db_statsfile(dbentry->databaseid, - dbentry->tables, - dbentry->functions, - permanent); - - break; - - /* - * 'Q' A PgStat_StatQueueEntry follows. (GPDB) - */ - case 'Q': - if (fread(&queuebuf, 1, sizeof(PgStat_StatQueueEntry), - fpin) != sizeof(PgStat_StatQueueEntry)) - { - ereport(pgStatRunningInCollector ? LOG : WARNING, - (errmsg("corrupted statistics file \"%s\"", - statfile))); - goto done; - } - - if (queuehash == NULL) - break; - - /* - * Add it to the queue hash. - */ - queueentry = (PgStat_StatQueueEntry *) hash_search(queuehash, - (void *) &queuebuf.queueid, - HASH_ENTER, &found); - - if (found) - { - ereport(pgStatRunningInCollector ? LOG : WARNING, - (errmsg("corrupted statistics file \"%s\"", - statfile))); - goto done; - } - - memcpy(queueentry, &queuebuf, sizeof(PgStat_StatQueueEntry)); - break; - /* - * 'R' A PgStat_StatReplSlotEntry struct describing a - * replication slot follows. - */ - case 'R': - { - PgStat_StatReplSlotEntry slotbuf; - PgStat_StatReplSlotEntry *slotent; - - if (fread(&slotbuf, 1, sizeof(PgStat_StatReplSlotEntry), fpin) - != sizeof(PgStat_StatReplSlotEntry)) - { - ereport(pgStatRunningInCollector ? LOG : WARNING, - (errmsg("corrupted statistics file \"%s\"", - statfile))); - goto done; - } - - /* Create hash table if we don't have it already. */ - if (replSlotStatHash == NULL) - { - HASHCTL hash_ctl; - - hash_ctl.keysize = sizeof(NameData); - hash_ctl.entrysize = sizeof(PgStat_StatReplSlotEntry); - hash_ctl.hcxt = pgStatLocalContext; - replSlotStatHash = hash_create("Replication slots hash", - PGSTAT_REPLSLOT_HASH_SIZE, - &hash_ctl, - HASH_ELEM | HASH_BLOBS | HASH_CONTEXT); - } - - slotent = (PgStat_StatReplSlotEntry *) hash_search(replSlotStatHash, - (void *) &slotbuf.slotname, - HASH_ENTER, NULL); - memcpy(slotent, &slotbuf, sizeof(PgStat_StatReplSlotEntry)); - break; - } - - case 'E': - goto done; - - default: - ereport(pgStatRunningInCollector ? LOG : WARNING, - (errmsg("corrupted statistics file \"%s\"", - statfile))); - goto done; - } - } - -done: - FreeFile(fpin); - - /* If requested to read the permanent file, also get rid of it. */ - if (permanent) - { - elog(DEBUG2, "removing permanent stats file \"%s\"", statfile); - unlink(statfile); - } - - return dbhash; -} - - -/* ---------- - * pgstat_read_db_statsfile() - - * - * Reads in the existing statistics collector file for the given database, - * filling the passed-in tables and functions hash tables. - * - * As in pgstat_read_statsfiles, if the permanent file is requested, it is - * removed after reading. - * - * Note: this code has the ability to skip storing per-table or per-function - * data, if NULL is passed for the corresponding hashtable. That's not used - * at the moment though. - * ---------- - */ -static void -pgstat_read_db_statsfile(Oid databaseid, HTAB *tabhash, HTAB *funchash, - bool permanent) -{ - PgStat_StatTabEntry *tabentry; - PgStat_StatTabEntry tabbuf; - PgStat_StatFuncEntry funcbuf; - PgStat_StatFuncEntry *funcentry; - FILE *fpin; - int32 format_id; - bool found; - char statfile[MAXPGPATH]; - - get_dbstat_filename(permanent, false, databaseid, statfile, MAXPGPATH); - - /* - * Try to open the stats file. If it doesn't exist, the backends simply - * return zero for anything and the collector simply starts from scratch - * with empty counters. - * - * ENOENT is a possibility if the stats collector is not running or has - * not yet written the stats file the first time. Any other failure - * condition is suspicious. - */ - if ((fpin = AllocateFile(statfile, PG_BINARY_R)) == NULL) - { - if (errno != ENOENT) - ereport(pgStatRunningInCollector ? LOG : WARNING, - (errcode_for_file_access(), - errmsg("could not open statistics file \"%s\": %m", - statfile))); - return; - } - - /* - * Verify it's of the expected format. - */ - if (fread(&format_id, 1, sizeof(format_id), fpin) != sizeof(format_id) || - format_id != PGSTAT_FILE_FORMAT_ID) - { - ereport(pgStatRunningInCollector ? LOG : WARNING, - (errmsg("corrupted statistics file \"%s\"", statfile))); - goto done; - } - - /* - * We found an existing collector stats file. Read it and put all the - * hashtable entries into place. - */ - for (;;) - { - switch (fgetc(fpin)) - { - /* - * 'T' A PgStat_StatTabEntry follows. - */ - case 'T': - if (fread(&tabbuf, 1, sizeof(PgStat_StatTabEntry), - fpin) != sizeof(PgStat_StatTabEntry)) - { - ereport(pgStatRunningInCollector ? LOG : WARNING, - (errmsg("corrupted statistics file \"%s\"", - statfile))); - goto done; - } - - /* - * Skip if table data not wanted. - */ - if (tabhash == NULL) - break; - - tabentry = (PgStat_StatTabEntry *) hash_search(tabhash, - (void *) &tabbuf.tableid, - HASH_ENTER, &found); - - if (found) - { - ereport(pgStatRunningInCollector ? LOG : WARNING, - (errmsg("corrupted statistics file \"%s\"", - statfile))); - goto done; - } - - memcpy(tabentry, &tabbuf, sizeof(tabbuf)); - break; - - /* - * 'F' A PgStat_StatFuncEntry follows. - */ - case 'F': - if (fread(&funcbuf, 1, sizeof(PgStat_StatFuncEntry), - fpin) != sizeof(PgStat_StatFuncEntry)) - { - ereport(pgStatRunningInCollector ? LOG : WARNING, - (errmsg("corrupted statistics file \"%s\"", - statfile))); - goto done; - } - - /* - * Skip if function data not wanted. - */ - if (funchash == NULL) - break; - - funcentry = (PgStat_StatFuncEntry *) hash_search(funchash, - (void *) &funcbuf.functionid, - HASH_ENTER, &found); - - if (found) - { - ereport(pgStatRunningInCollector ? LOG : WARNING, - (errmsg("corrupted statistics file \"%s\"", - statfile))); - goto done; - } - - memcpy(funcentry, &funcbuf, sizeof(funcbuf)); - break; - - /* - * 'E' The EOF marker of a complete stats file. - */ - case 'E': - goto done; - - default: - ereport(pgStatRunningInCollector ? LOG : WARNING, - (errmsg("corrupted statistics file \"%s\"", - statfile))); - goto done; - } - } - -done: - FreeFile(fpin); - - if (permanent) - { - elog(DEBUG2, "removing permanent stats file \"%s\"", statfile); - unlink(statfile); - } -} - -/* ---------- - * pgstat_read_db_statsfile_timestamp() - - * - * Attempt to determine the timestamp of the last db statfile write. - * Returns true if successful; the timestamp is stored in *ts. The caller must - * rely on timestamp stored in *ts iff the function returns true. - * - * This needs to be careful about handling databases for which no stats file - * exists, such as databases without a stat entry or those not yet written: - * - * - if there's a database entry in the global file, return the corresponding - * stats_timestamp value. - * - * - if there's no db stat entry (e.g. for a new or inactive database), - * there's no stats_timestamp value, but also nothing to write so we return - * the timestamp of the global statfile. - * ---------- - */ -static bool -pgstat_read_db_statsfile_timestamp(Oid databaseid, bool permanent, - TimestampTz *ts) -{ - PgStat_StatDBEntry dbentry; - PgStat_StatQueueEntry queuebuf; /* GPDB */ - PgStat_GlobalStats myGlobalStats; - PgStat_ArchiverStats myArchiverStats; - PgStat_WalStats myWalStats; - PgStat_SLRUStats mySLRUStats[SLRU_NUM_ELEMENTS]; - PgStat_StatReplSlotEntry myReplSlotStats; - FILE *fpin; - int32 format_id; - const char *statfile = permanent ? PGSTAT_STAT_PERMANENT_FILENAME : pgstat_stat_filename; - - /* - * Try to open the stats file. As above, anything but ENOENT is worthy of - * complaining about. - */ - if ((fpin = AllocateFile(statfile, PG_BINARY_R)) == NULL) - { - if (errno != ENOENT) - ereport(pgStatRunningInCollector ? LOG : WARNING, - (errcode_for_file_access(), - errmsg("could not open statistics file \"%s\": %m", - statfile))); - return false; - } - - /* - * Verify it's of the expected format. - */ - if (fread(&format_id, 1, sizeof(format_id), fpin) != sizeof(format_id) || - format_id != PGSTAT_FILE_FORMAT_ID) - { - ereport(pgStatRunningInCollector ? LOG : WARNING, - (errmsg("corrupted statistics file \"%s\"", statfile))); - FreeFile(fpin); - return false; - } - - /* - * Read global stats struct - */ - if (fread(&myGlobalStats, 1, sizeof(myGlobalStats), - fpin) != sizeof(myGlobalStats)) - { - ereport(pgStatRunningInCollector ? LOG : WARNING, - (errmsg("corrupted statistics file \"%s\"", statfile))); - FreeFile(fpin); - return false; - } - - /* - * Read archiver stats struct - */ - if (fread(&myArchiverStats, 1, sizeof(myArchiverStats), - fpin) != sizeof(myArchiverStats)) - { - ereport(pgStatRunningInCollector ? LOG : WARNING, - (errmsg("corrupted statistics file \"%s\"", statfile))); - FreeFile(fpin); - return false; - } - - /* - * Read WAL stats struct - */ - if (fread(&myWalStats, 1, sizeof(myWalStats), fpin) != sizeof(myWalStats)) - { - ereport(pgStatRunningInCollector ? LOG : WARNING, - (errmsg("corrupted statistics file \"%s\"", statfile))); - FreeFile(fpin); - return false; - } - - /* - * Read SLRU stats struct - */ - if (fread(mySLRUStats, 1, sizeof(mySLRUStats), fpin) != sizeof(mySLRUStats)) - { - ereport(pgStatRunningInCollector ? LOG : WARNING, - (errmsg("corrupted statistics file \"%s\"", statfile))); - FreeFile(fpin); - return false; - } - - /* By default, we're going to return the timestamp of the global file. */ - *ts = myGlobalStats.stats_timestamp; - - /* - * We found an existing collector stats file. Read it and look for a - * record for the requested database. If found, use its timestamp. - */ - for (;;) - { - switch (fgetc(fpin)) - { - /* - * 'D' A PgStat_StatDBEntry struct describing a database - * follows. - */ - case 'D': - if (fread(&dbentry, 1, offsetof(PgStat_StatDBEntry, tables), - fpin) != offsetof(PgStat_StatDBEntry, tables)) - { - ereport(pgStatRunningInCollector ? LOG : WARNING, - (errmsg("corrupted statistics file \"%s\"", - statfile))); - FreeFile(fpin); - return false; - } - - /* - * If this is the DB we're looking for, save its timestamp and - * we're done. - */ - if (dbentry.databaseid == databaseid) - { - *ts = dbentry.stats_timestamp; - goto done; - } - - break; - - /* - * 'Q' A PgStat_StatQueueEntry follows. (GPDB) - */ - case 'Q': - if (fread(&queuebuf, 1, sizeof(PgStat_StatQueueEntry), - fpin) != sizeof(PgStat_StatQueueEntry)) - { - ereport(pgStatRunningInCollector ? LOG : WARNING, - (errmsg("corrupted statistics file \"%s\"", - statfile))); - goto done; - } - break; - /* - * 'R' A PgStat_StatReplSlotEntry struct describing a - * replication slot follows. - */ - case 'R': - if (fread(&myReplSlotStats, 1, sizeof(PgStat_StatReplSlotEntry), fpin) - != sizeof(PgStat_StatReplSlotEntry)) - { - ereport(pgStatRunningInCollector ? LOG : WARNING, - (errmsg("corrupted statistics file \"%s\"", - statfile))); - FreeFile(fpin); - return false; - } - break; - - case 'E': - goto done; - - default: - { - ereport(pgStatRunningInCollector ? LOG : WARNING, - (errmsg("corrupted statistics file \"%s\"", - statfile))); - FreeFile(fpin); - return false; - } - } - } - -done: - FreeFile(fpin); - return true; -} - -/* - * If not already done, read the statistics collector stats file into - * some hash tables. The results will be kept until pgstat_clear_snapshot() - * is called (typically, at end of transaction). - */ -static void -backend_read_statsfile(void) -{ - TimestampTz min_ts = 0; - TimestampTz ref_ts = 0; - Oid inquiry_db; - int count; - - /* already read it? */ - if (pgStatDBHash) - return; - Assert(!pgStatRunningInCollector); - - /* - * In a normal backend, we check staleness of the data for our own DB, and - * so we send MyDatabaseId in inquiry messages. In the autovac launcher, - * check staleness of the shared-catalog data, and send InvalidOid in - * inquiry messages so as not to force writing unnecessary data. - */ - if (IsAutoVacuumLauncherProcess()) - inquiry_db = InvalidOid; - else - inquiry_db = MyDatabaseId; - - /* - * Loop until fresh enough stats file is available or we ran out of time. - * The stats inquiry message is sent repeatedly in case collector drops - * it; but not every single time, as that just swamps the collector. - */ - for (count = 0; count < PGSTAT_POLL_LOOP_COUNT; count++) - { - bool ok; - TimestampTz file_ts = 0; - TimestampTz cur_ts; - - CHECK_FOR_INTERRUPTS(); - - ok = pgstat_read_db_statsfile_timestamp(inquiry_db, false, &file_ts); - - cur_ts = GetCurrentTimestamp(); - /* Calculate min acceptable timestamp, if we didn't already */ - if (count == 0 || cur_ts < ref_ts) - { - /* - * We set the minimum acceptable timestamp to PGSTAT_STAT_INTERVAL - * msec before now. This indirectly ensures that the collector - * needn't write the file more often than PGSTAT_STAT_INTERVAL. In - * an autovacuum worker, however, we want a lower delay to avoid - * using stale data, so we use PGSTAT_RETRY_DELAY (since the - * number of workers is low, this shouldn't be a problem). - * - * We don't recompute min_ts after sleeping, except in the - * unlikely case that cur_ts went backwards. So we might end up - * accepting a file a bit older than PGSTAT_STAT_INTERVAL. In - * practice that shouldn't happen, though, as long as the sleep - * time is less than PGSTAT_STAT_INTERVAL; and we don't want to - * tell the collector that our cutoff time is less than what we'd - * actually accept. - */ - ref_ts = cur_ts; - if (IsAutoVacuumWorkerProcess()) - min_ts = TimestampTzPlusMilliseconds(ref_ts, - -PGSTAT_RETRY_DELAY); - else - min_ts = TimestampTzPlusMilliseconds(ref_ts, - -PGSTAT_STAT_INTERVAL); - } - - /* - * If the file timestamp is actually newer than cur_ts, we must have - * had a clock glitch (system time went backwards) or there is clock - * skew between our processor and the stats collector's processor. - * Accept the file, but send an inquiry message anyway to make - * pgstat_recv_inquiry do a sanity check on the collector's time. - */ - if (ok && file_ts > cur_ts) - { - /* - * A small amount of clock skew between processors isn't terribly - * surprising, but a large difference is worth logging. We - * arbitrarily define "large" as 1000 msec. - */ - if (file_ts >= TimestampTzPlusMilliseconds(cur_ts, 1000)) - { - char *filetime; - char *mytime; - - /* Copy because timestamptz_to_str returns a static buffer */ - filetime = pstrdup(timestamptz_to_str(file_ts)); - mytime = pstrdup(timestamptz_to_str(cur_ts)); - ereport(LOG, - (errmsg("statistics collector's time %s is later than backend local time %s", - filetime, mytime))); - pfree(filetime); - pfree(mytime); - } - - pgstat_send_inquiry(cur_ts, min_ts, inquiry_db); - break; - } - - /* Normal acceptance case: file is not older than cutoff time */ - if (ok && file_ts >= min_ts) - break; - - /* Not there or too old, so kick the collector and wait a bit */ - if ((count % PGSTAT_INQ_LOOP_COUNT) == 0) - pgstat_send_inquiry(cur_ts, min_ts, inquiry_db); - - pg_usleep(PGSTAT_RETRY_DELAY * 1000L); - } - - if (count >= PGSTAT_POLL_LOOP_COUNT) - ereport(LOG, - (errmsg("using stale statistics instead of current ones " - "because stats collector is not responding"))); - - /* - * Autovacuum launcher wants stats about all databases, but a shallow read - * is sufficient. Regular backends want a deep read for just the tables - * they can see (MyDatabaseId + shared catalogs). - */ - if (IsAutoVacuumLauncherProcess()) - pgStatDBHash = pgstat_read_statsfiles(InvalidOid, false, false); - else - pgStatDBHash = pgstat_read_statsfiles(MyDatabaseId, false, true); -} - - -/* ---------- - * pgstat_setup_memcxt() - - * - * Create pgStatLocalContext, if not already done. - * ---------- - */ -static void -pgstat_setup_memcxt(void) -{ - if (!pgStatLocalContext) - pgStatLocalContext = AllocSetContextCreate(TopMemoryContext, - "Statistics snapshot", - ALLOCSET_SMALL_SIZES); -} - - -/* ---------- - * pgstat_clear_snapshot() - - * - * Discard any data collected in the current transaction. Any subsequent - * request will cause new snapshots to be read. - * - * This is also invoked during transaction commit or abort to discard - * the no-longer-wanted snapshot. - * ---------- - */ -void -pgstat_clear_snapshot(void) -{ - /* Release memory, if any was allocated */ - if (pgStatLocalContext) - MemoryContextDelete(pgStatLocalContext); - - /* Reset variables */ - pgStatLocalContext = NULL; - pgStatDBHash = NULL; - replSlotStatHash = NULL; - - /* - * Historically the backend_status.c facilities lived in this file, and - * were reset with the same function. For now keep it that way, and - * forward the reset request. - */ - pgstat_clear_backend_activity_snapshot(); -} - - -/* ---------- - * pgstat_recv_inquiry() - - * - * Process stat inquiry requests. - * ---------- - */ -static void -pgstat_recv_inquiry(PgStat_MsgInquiry *msg, int len) -{ - PgStat_StatDBEntry *dbentry; - - elog(DEBUG2, "received inquiry for database %u", msg->databaseid); - - /* - * If there's already a write request for this DB, there's nothing to do. - * - * Note that if a request is found, we return early and skip the below - * check for clock skew. This is okay, since the only way for a DB - * request to be present in the list is that we have been here since the - * last write round. It seems sufficient to check for clock skew once per - * write round. - */ - if (list_member_oid(pending_write_requests, msg->databaseid)) - return; - - /* - * Check to see if we last wrote this database at a time >= the requested - * cutoff time. If so, this is a stale request that was generated before - * we updated the DB file, and we don't need to do so again. - * - * If the requestor's local clock time is older than stats_timestamp, we - * should suspect a clock glitch, ie system time going backwards; though - * the more likely explanation is just delayed message receipt. It is - * worth expending a GetCurrentTimestamp call to be sure, since a large - * retreat in the system clock reading could otherwise cause us to neglect - * to update the stats file for a long time. - */ - dbentry = pgstat_get_db_entry(msg->databaseid, false); - if (dbentry == NULL) - { - /* - * We have no data for this DB. Enter a write request anyway so that - * the global stats will get updated. This is needed to prevent - * backend_read_statsfile from waiting for data that we cannot supply, - * in the case of a new DB that nobody has yet reported any stats for. - * See the behavior of pgstat_read_db_statsfile_timestamp. - */ - } - else if (msg->clock_time < dbentry->stats_timestamp) - { - TimestampTz cur_ts = GetCurrentTimestamp(); - - if (cur_ts < dbentry->stats_timestamp) - { - /* - * Sure enough, time went backwards. Force a new stats file write - * to get back in sync; but first, log a complaint. - */ - char *writetime; - char *mytime; - - /* Copy because timestamptz_to_str returns a static buffer */ - writetime = pstrdup(timestamptz_to_str(dbentry->stats_timestamp)); - mytime = pstrdup(timestamptz_to_str(cur_ts)); - ereport(LOG, - (errmsg("stats_timestamp %s is later than collector's time %s for database %u", - writetime, mytime, dbentry->databaseid))); - pfree(writetime); - pfree(mytime); - } - else - { - /* - * Nope, it's just an old request. Assuming msg's clock_time is - * >= its cutoff_time, it must be stale, so we can ignore it. - */ - return; - } - } - else if (msg->cutoff_time <= dbentry->stats_timestamp) - { - /* Stale request, ignore it */ - return; - } - - /* - * We need to write this DB, so create a request. - */ - pending_write_requests = lappend_oid(pending_write_requests, - msg->databaseid); -} - - -/* ---------- - * pgstat_recv_tabstat() - - * - * Count what the backend has done. - * ---------- - */ -static void -pgstat_recv_tabstat(PgStat_MsgTabstat *msg, int len) -{ - PgStat_StatDBEntry *dbentry; - PgStat_StatTabEntry *tabentry; - int i; - bool found; - - dbentry = pgstat_get_db_entry(msg->m_databaseid, true); - - /* - * Update database-wide stats. - */ - dbentry->n_xact_commit += (PgStat_Counter) (msg->m_xact_commit); - dbentry->n_xact_rollback += (PgStat_Counter) (msg->m_xact_rollback); - dbentry->n_block_read_time += msg->m_block_read_time; - dbentry->n_block_write_time += msg->m_block_write_time; - - dbentry->total_session_time += msg->m_session_time; - dbentry->total_active_time += msg->m_active_time; - dbentry->total_idle_in_xact_time += msg->m_idle_in_xact_time; - - /* - * Process all table entries in the message. - */ - for (i = 0; i < msg->m_nentries; i++) - { - PgStat_TableEntry *tabmsg = &(msg->m_entry[i]); - - tabentry = (PgStat_StatTabEntry *) hash_search(dbentry->tables, - (void *) &(tabmsg->t_id), - HASH_ENTER, &found); - - if (!found) - { - /* - * If it's a new table entry, initialize counters to the values we - * just got. - */ - tabentry->numscans = tabmsg->t_counts.t_numscans; - tabentry->tuples_returned = tabmsg->t_counts.t_tuples_returned; - tabentry->tuples_fetched = tabmsg->t_counts.t_tuples_fetched; - tabentry->tuples_inserted = tabmsg->t_counts.t_tuples_inserted; - tabentry->tuples_updated = tabmsg->t_counts.t_tuples_updated; - tabentry->tuples_deleted = tabmsg->t_counts.t_tuples_deleted; - tabentry->tuples_hot_updated = tabmsg->t_counts.t_tuples_hot_updated; - tabentry->n_live_tuples = tabmsg->t_counts.t_delta_live_tuples; - tabentry->n_dead_tuples = tabmsg->t_counts.t_delta_dead_tuples; - tabentry->changes_since_analyze = tabmsg->t_counts.t_changed_tuples; - tabentry->inserts_since_vacuum = tabmsg->t_counts.t_tuples_inserted; - tabentry->blocks_fetched = tabmsg->t_counts.t_blocks_fetched; - tabentry->blocks_hit = tabmsg->t_counts.t_blocks_hit; - - tabentry->vacuum_timestamp = 0; - tabentry->vacuum_count = 0; - tabentry->autovac_vacuum_timestamp = 0; - tabentry->autovac_vacuum_count = 0; - tabentry->analyze_timestamp = 0; - tabentry->analyze_count = 0; - tabentry->autovac_analyze_timestamp = 0; - tabentry->autovac_analyze_count = 0; - } - else - { - /* - * Otherwise add the values to the existing entry. - */ - tabentry->numscans += tabmsg->t_counts.t_numscans; - tabentry->tuples_returned += tabmsg->t_counts.t_tuples_returned; - tabentry->tuples_fetched += tabmsg->t_counts.t_tuples_fetched; - tabentry->tuples_inserted += tabmsg->t_counts.t_tuples_inserted; - tabentry->tuples_updated += tabmsg->t_counts.t_tuples_updated; - tabentry->tuples_deleted += tabmsg->t_counts.t_tuples_deleted; - tabentry->tuples_hot_updated += tabmsg->t_counts.t_tuples_hot_updated; - /* If table was truncated, first reset the live/dead counters */ - if (tabmsg->t_counts.t_truncated) - { - tabentry->n_live_tuples = 0; - tabentry->n_dead_tuples = 0; - tabentry->inserts_since_vacuum = 0; - } - tabentry->n_live_tuples += tabmsg->t_counts.t_delta_live_tuples; - tabentry->n_dead_tuples += tabmsg->t_counts.t_delta_dead_tuples; - tabentry->changes_since_analyze += tabmsg->t_counts.t_changed_tuples; - tabentry->inserts_since_vacuum += tabmsg->t_counts.t_tuples_inserted; - tabentry->blocks_fetched += tabmsg->t_counts.t_blocks_fetched; - tabentry->blocks_hit += tabmsg->t_counts.t_blocks_hit; - } - - /* Clamp n_live_tuples in case of negative delta_live_tuples */ - tabentry->n_live_tuples = Max(tabentry->n_live_tuples, 0); - /* Likewise for n_dead_tuples */ - tabentry->n_dead_tuples = Max(tabentry->n_dead_tuples, 0); - - /* - * Add per-table stats to the per-database entry, too. - */ - dbentry->n_tuples_returned += tabmsg->t_counts.t_tuples_returned; - dbentry->n_tuples_fetched += tabmsg->t_counts.t_tuples_fetched; - dbentry->n_tuples_inserted += tabmsg->t_counts.t_tuples_inserted; - dbentry->n_tuples_updated += tabmsg->t_counts.t_tuples_updated; - dbentry->n_tuples_deleted += tabmsg->t_counts.t_tuples_deleted; - dbentry->n_blocks_fetched += tabmsg->t_counts.t_blocks_fetched; - dbentry->n_blocks_hit += tabmsg->t_counts.t_blocks_hit; - } -} - - -/* ---------- - * pgstat_recv_tabpurge() - - * - * Arrange for dead table removal. - * ---------- - */ -static void -pgstat_recv_tabpurge(PgStat_MsgTabpurge *msg, int len) -{ - PgStat_StatDBEntry *dbentry; - int i; - - dbentry = pgstat_get_db_entry(msg->m_databaseid, false); - - /* - * No need to purge if we don't even know the database. - */ - if (!dbentry || !dbentry->tables) - return; - - /* - * Process all table entries in the message. - */ - for (i = 0; i < msg->m_nentries; i++) - { - /* Remove from hashtable if present; we don't care if it's not. */ - (void) hash_search(dbentry->tables, - (void *) &(msg->m_tableid[i]), - HASH_REMOVE, NULL); - } -} - - -/* ---------- - * pgstat_recv_dropdb() - - * - * Arrange for dead database removal - * ---------- - */ -static void -pgstat_recv_dropdb(PgStat_MsgDropdb *msg, int len) -{ - Oid dbid = msg->m_databaseid; - PgStat_StatDBEntry *dbentry; - - /* - * Lookup the database in the hashtable. - */ - dbentry = pgstat_get_db_entry(dbid, false); - - /* - * If found, remove it (along with the db statfile). - */ - if (dbentry) - { - char statfile[MAXPGPATH]; - - get_dbstat_filename(false, false, dbid, statfile, MAXPGPATH); - - elog(DEBUG2, "removing stats file \"%s\"", statfile); - unlink(statfile); - - if (dbentry->tables != NULL) - hash_destroy(dbentry->tables); - if (dbentry->functions != NULL) - hash_destroy(dbentry->functions); - - if (hash_search(pgStatDBHash, - (void *) &dbid, - HASH_REMOVE, NULL) == NULL) - ereport(ERROR, - (errmsg("database hash table corrupted during cleanup --- abort"))); - } -} - - -/* ---------- - * pgstat_recv_resetcounter() - - * - * Reset the statistics for the specified database. - * ---------- - */ -static void -pgstat_recv_resetcounter(PgStat_MsgResetcounter *msg, int len) -{ - PgStat_StatDBEntry *dbentry; - - /* - * Lookup the database in the hashtable. Nothing to do if not there. - */ - dbentry = pgstat_get_db_entry(msg->m_databaseid, false); - - if (!dbentry) - return; - - /* - * We simply throw away all the database's table entries by recreating a - * new hash table for them. - */ - if (dbentry->tables != NULL) - hash_destroy(dbentry->tables); - if (dbentry->functions != NULL) - hash_destroy(dbentry->functions); - - dbentry->tables = NULL; - dbentry->functions = NULL; - - /* - * Reset database-level stats, too. This creates empty hash tables for - * tables and functions. - */ - reset_dbentry_counters(dbentry); -} - -/* ---------- - * pgstat_recv_resetsharedcounter() - - * - * Reset some shared statistics of the cluster. - * ---------- - */ -static void -pgstat_recv_resetsharedcounter(PgStat_MsgResetsharedcounter *msg, int len) -{ - if (msg->m_resettarget == RESET_BGWRITER) - { - /* Reset the global background writer statistics for the cluster. */ - memset(&globalStats, 0, sizeof(globalStats)); - globalStats.stat_reset_timestamp = GetCurrentTimestamp(); - } - else if (msg->m_resettarget == RESET_ARCHIVER) - { - /* Reset the archiver statistics for the cluster. */ - memset(&archiverStats, 0, sizeof(archiverStats)); - archiverStats.stat_reset_timestamp = GetCurrentTimestamp(); - } - else if (msg->m_resettarget == RESET_WAL) - { - /* Reset the WAL statistics for the cluster. */ - memset(&walStats, 0, sizeof(walStats)); - walStats.stat_reset_timestamp = GetCurrentTimestamp(); - } - - /* - * Presumably the sender of this message validated the target, don't - * complain here if it's not valid - */ -} - -/* ---------- - * pgstat_recv_resetsinglecounter() - - * - * Reset a statistics for a single object - * ---------- - */ -static void -pgstat_recv_resetsinglecounter(PgStat_MsgResetsinglecounter *msg, int len) -{ - PgStat_StatDBEntry *dbentry; - - dbentry = pgstat_get_db_entry(msg->m_databaseid, false); - - if (!dbentry) - return; - - /* Set the reset timestamp for the whole database */ - dbentry->stat_reset_timestamp = GetCurrentTimestamp(); - - /* Remove object if it exists, ignore it if not */ - if (msg->m_resettype == RESET_TABLE) - (void) hash_search(dbentry->tables, (void *) &(msg->m_objectid), - HASH_REMOVE, NULL); - else if (msg->m_resettype == RESET_FUNCTION) - (void) hash_search(dbentry->functions, (void *) &(msg->m_objectid), - HASH_REMOVE, NULL); -} - -/* ---------- - * pgstat_recv_resetslrucounter() - - * - * Reset some SLRU statistics of the cluster. - * ---------- - */ -static void -pgstat_recv_resetslrucounter(PgStat_MsgResetslrucounter *msg, int len) -{ - int i; - TimestampTz ts = GetCurrentTimestamp(); - - for (i = 0; i < SLRU_NUM_ELEMENTS; i++) - { - /* reset entry with the given index, or all entries (index is -1) */ - if ((msg->m_index == -1) || (msg->m_index == i)) - { - memset(&slruStats[i], 0, sizeof(slruStats[i])); - slruStats[i].stat_reset_timestamp = ts; - } - } -} - -/* ---------- - * pgstat_recv_resetreplslotcounter() - - * - * Reset some replication slot statistics of the cluster. - * ---------- - */ -static void -pgstat_recv_resetreplslotcounter(PgStat_MsgResetreplslotcounter *msg, - int len) -{ - PgStat_StatReplSlotEntry *slotent; - TimestampTz ts; - - /* Return if we don't have replication slot statistics */ - if (replSlotStatHash == NULL) - return; - - ts = GetCurrentTimestamp(); - if (msg->clearall) - { - HASH_SEQ_STATUS sstat; - - hash_seq_init(&sstat, replSlotStatHash); - while ((slotent = (PgStat_StatReplSlotEntry *) hash_seq_search(&sstat)) != NULL) - pgstat_reset_replslot(slotent, ts); - } - else - { - /* Get the slot statistics to reset */ - slotent = pgstat_get_replslot_entry(msg->m_slotname, false); - - /* - * Nothing to do if the given slot entry is not found. This could - * happen when the slot with the given name is removed and the - * corresponding statistics entry is also removed before receiving the - * reset message. - */ - if (!slotent) - return; - - /* Reset the stats for the requested replication slot */ - pgstat_reset_replslot(slotent, ts); - } -} - - -/* ---------- - * pgstat_recv_autovac() - - * - * Process an autovacuum signaling message. - * ---------- - */ -static void -pgstat_recv_autovac(PgStat_MsgAutovacStart *msg, int len) -{ - PgStat_StatDBEntry *dbentry; - - /* - * Store the last autovacuum time in the database's hashtable entry. - */ - dbentry = pgstat_get_db_entry(msg->m_databaseid, true); - - dbentry->last_autovac_time = msg->m_start_time; -} - -/* ---------- - * pgstat_recv_vacuum() - - * - * Process a VACUUM message. - * ---------- - */ -static void -pgstat_recv_vacuum(PgStat_MsgVacuum *msg, int len) -{ - PgStat_StatDBEntry *dbentry; - PgStat_StatTabEntry *tabentry; - - /* - * Store the data in the table's hashtable entry. - */ - dbentry = pgstat_get_db_entry(msg->m_databaseid, true); - - tabentry = pgstat_get_tab_entry(dbentry, msg->m_tableoid, true); - - tabentry->n_live_tuples = msg->m_live_tuples; - tabentry->n_dead_tuples = msg->m_dead_tuples; - - /* - * It is quite possible that a non-aggressive VACUUM ended up skipping - * various pages, however, we'll zero the insert counter here regardless. - * It's currently used only to track when we need to perform an "insert" - * autovacuum, which are mainly intended to freeze newly inserted tuples. - * Zeroing this may just mean we'll not try to vacuum the table again - * until enough tuples have been inserted to trigger another insert - * autovacuum. An anti-wraparound autovacuum will catch any persistent - * stragglers. - */ - tabentry->inserts_since_vacuum = 0; - - if (msg->m_autovacuum) - { - tabentry->autovac_vacuum_timestamp = msg->m_vacuumtime; - tabentry->autovac_vacuum_count++; - } - else - { - tabentry->vacuum_timestamp = msg->m_vacuumtime; - tabentry->vacuum_count++; - } -} - -/* ---------- - * pgstat_recv_analyze() - - * - * Process an ANALYZE message. - * ---------- - */ -static void -pgstat_recv_analyze(PgStat_MsgAnalyze *msg, int len) -{ - PgStat_StatDBEntry *dbentry; - PgStat_StatTabEntry *tabentry; - - /* - * Store the data in the table's hashtable entry. - */ - dbentry = pgstat_get_db_entry(msg->m_databaseid, true); - - tabentry = pgstat_get_tab_entry(dbentry, msg->m_tableoid, true); - - tabentry->n_live_tuples = msg->m_live_tuples; - tabentry->n_dead_tuples = msg->m_dead_tuples; - - /* - * If commanded, reset changes_since_analyze to zero. This forgets any - * changes that were committed while the ANALYZE was in progress, but we - * have no good way to estimate how many of those there were. - */ - if (msg->m_resetcounter) - tabentry->changes_since_analyze = 0; - - if (msg->m_autovacuum) - { - tabentry->autovac_analyze_timestamp = msg->m_analyzetime; - tabentry->autovac_analyze_count++; - } - else - { - tabentry->analyze_timestamp = msg->m_analyzetime; - tabentry->analyze_count++; - } -} - - -/* ---------- - * pgstat_recv_archiver() - - * - * Process a ARCHIVER message. - * ---------- - */ -static void -pgstat_recv_archiver(PgStat_MsgArchiver *msg, int len) -{ - if (msg->m_failed) - { - /* Failed archival attempt */ - ++archiverStats.failed_count; - memcpy(archiverStats.last_failed_wal, msg->m_xlog, - sizeof(archiverStats.last_failed_wal)); - archiverStats.last_failed_timestamp = msg->m_timestamp; - } - else - { - /* Successful archival operation */ - ++archiverStats.archived_count; - memcpy(archiverStats.last_archived_wal, msg->m_xlog, - sizeof(archiverStats.last_archived_wal)); - archiverStats.last_archived_timestamp = msg->m_timestamp; - } -} - -/* ---------- - * pgstat_recv_bgwriter() - - * - * Process a BGWRITER message. - * ---------- - */ -static void -pgstat_recv_bgwriter(PgStat_MsgBgWriter *msg, int len) -{ - globalStats.timed_checkpoints += msg->m_timed_checkpoints; - globalStats.requested_checkpoints += msg->m_requested_checkpoints; - globalStats.checkpoint_write_time += msg->m_checkpoint_write_time; - globalStats.checkpoint_sync_time += msg->m_checkpoint_sync_time; - globalStats.buf_written_checkpoints += msg->m_buf_written_checkpoints; - globalStats.buf_written_clean += msg->m_buf_written_clean; - globalStats.maxwritten_clean += msg->m_maxwritten_clean; - globalStats.buf_written_backend += msg->m_buf_written_backend; - globalStats.buf_fsync_backend += msg->m_buf_fsync_backend; - globalStats.buf_alloc += msg->m_buf_alloc; -} - - -/* - * GPDB: Lookup the hash table entry for the specified resource queue. If no hash - * table entry exists, initialize it, if the create parameter is true. - * Else, return NULL. - */ -static PgStat_StatQueueEntry * -pgstat_get_queue_entry(Oid queueid, bool create) -{ - PgStat_StatQueueEntry *result; - bool found; - HASHACTION action = (create ? HASH_ENTER : HASH_FIND); - - /* Lookup or create the hash table entry for this queue */ - result = (PgStat_StatQueueEntry *) hash_search(pgStatQueueHash, - &queueid, - action, &found); - - if (!create && !found) - return NULL; - - /* If not found, initialize the new one. */ - if (!found) - { - result->queueid = queueid; - result->n_queries_exec = 0; - result->n_queries_wait = 0; - result->elapsed_exec = 0; - result->elapsed_wait = 0; - } - - return result; -} - -/* ---------- - * pgstat_recv_queuestat() - - * - * Process resource queue activity for a backend. - * ---------- - */ -static void -pgstat_recv_queuestat(PgStat_MsgQueuestat *msg, int len) -{ - PgStat_StatQueueEntry *queueentry; - - /* Get or create an entry for this resource queue. */ - queueentry = pgstat_get_queue_entry(msg->m_queueid, true); - - /* Update the metrics. */ - queueentry->n_queries_exec += msg->m_queries_exec; - queueentry->n_queries_wait += msg->m_queries_wait; - queueentry->elapsed_exec += msg->m_elapsed_exec; - queueentry->elapsed_wait += msg->m_elapsed_wait; -} - - -/* ---------- - * pgstat_init_localportalhash() - - * - * Cache for portal statistics for a backend. - * ---------- - */ -void -pgstat_init_localportalhash(void) -{ - HASHCTL info; - int hash_flags; - - info.keysize = sizeof(uint32); - info.entrysize = sizeof(PgStat_StatPortalEntry); - info.hash = tag_hash; - hash_flags = (HASH_ELEM | HASH_FUNCTION); - - localStatPortalHash = hash_create("Local Stat Portal Hash", - 1, - &info, - hash_flags); - - return; -} - - -/* ---------- - * pgstat_getportalentry() - - * - * Return the (PgStat_StatPortalEntry *) for a given portal (and backend). - * ---------- - */ -PgStat_StatPortalEntry * -pgstat_getportalentry(uint32 portalid, Oid queueid) -{ - PgStat_StatPortalEntry *portalentry; - - bool found; - - portalentry = hash_search(localStatPortalHash, - (void *) &portalid, - HASH_ENTER, &found); - - Assert(portalentry != NULL); - - /* Initialize if this we have not seen this portal before! */ - if (!found || portalentry->queueentry.queueid == InvalidOid) - { - portalentry->portalid = portalid; - portalentry->queueentry.queueid = queueid; - portalentry->queueentry.n_queries_exec = 0; - portalentry->queueentry.n_queries_wait = 0; - portalentry->queueentry.elapsed_exec = 0; - portalentry->queueentry.elapsed_wait = 0; - } - - return portalentry; -} - - -/* ---------- - * pgstat_report_queuestat() - - * - * Called from tcop/postgres.c to send the so far collected - * per resource queue statistics to the collector. - * ---------- - */ -void -pgstat_report_queuestat() -{ - HASH_SEQ_STATUS hstat; - PgStat_StatPortalEntry *pentry; - PgStat_MsgQueuestat msg; - - /* Not collecting queue stats or collector disabled. */ - if (pgStatSock < 0 || !pgstat_collect_queuelevel) - return; - - /* Do a sequential scan through the local portal/queue hash*/ - hash_seq_init(&hstat, localStatPortalHash); - while ((pentry = (PgStat_StatPortalEntry *) hash_seq_search(&hstat)) != NULL) - { - /* Skip if message payload will be trivial. */ - if (pentry->queueentry.n_queries_exec == 0 && - pentry->queueentry.n_queries_wait == 0 && - pentry->queueentry.elapsed_exec == 0 && - pentry->queueentry.elapsed_wait == 0) - continue; - - /* Initialize a message to send to the collector. */ - pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_QUEUESTAT); - msg.m_queueid = pentry->queueentry.queueid; - msg.m_queries_exec = pentry->queueentry.n_queries_exec; - msg.m_queries_wait = pentry->queueentry.n_queries_wait; - msg.m_elapsed_exec = pentry->queueentry.elapsed_exec; - msg.m_elapsed_wait = pentry->queueentry.elapsed_wait; - - /* Reset the counters for this entry. */ - pentry->queueentry.queueid = InvalidOid; - pentry->queueentry.n_queries_exec = 0; - pentry->queueentry.n_queries_wait = 0; - pentry->queueentry.elapsed_exec = 0; - pentry->queueentry.elapsed_wait = 0; - - pgstat_send(&msg, sizeof(msg)); - } -} - - -/* ---------- - * pgstat_fetch_stat_queueentry() - - * - * Support function for the SQL-callable pgstat* functions. Returns - * the collected statistics for one resource queue or NULL. NULL doesn't mean - * that the queue doesn't exist, it is just not yet known by the - * collector, so the caller is better off to report ZERO instead. - * ---------- - */ -PgStat_StatQueueEntry * -pgstat_fetch_stat_queueentry(Oid queueid) -{ - /* - * If not done for this transaction, read the statistics collector stats - * file into some hash tables. - */ - backend_read_statsfile(); - - /* - * Lookup the requested database; return NULL if not found - */ - return (PgStat_StatQueueEntry *) hash_search(pgStatQueueHash, - (void *) &queueid, - HASH_FIND, NULL); -} - - -/* ---------- - * pgstat_recv_wal() - - * - * Process a WAL message. - * ---------- - */ -static void -pgstat_recv_wal(PgStat_MsgWal *msg, int len) -{ - walStats.wal_records += msg->m_wal_records; - walStats.wal_fpi += msg->m_wal_fpi; - walStats.wal_bytes += msg->m_wal_bytes; - walStats.wal_buffers_full += msg->m_wal_buffers_full; - walStats.wal_write += msg->m_wal_write; - walStats.wal_sync += msg->m_wal_sync; - walStats.wal_write_time += msg->m_wal_write_time; - walStats.wal_sync_time += msg->m_wal_sync_time; -} - -/* ---------- - * pgstat_recv_slru() - - * - * Process a SLRU message. - * ---------- - */ -static void -pgstat_recv_slru(PgStat_MsgSLRU *msg, int len) -{ - slruStats[msg->m_index].blocks_zeroed += msg->m_blocks_zeroed; - slruStats[msg->m_index].blocks_hit += msg->m_blocks_hit; - slruStats[msg->m_index].blocks_read += msg->m_blocks_read; - slruStats[msg->m_index].blocks_written += msg->m_blocks_written; - slruStats[msg->m_index].blocks_exists += msg->m_blocks_exists; - slruStats[msg->m_index].flush += msg->m_flush; - slruStats[msg->m_index].truncate += msg->m_truncate; -} - -/* ---------- - * pgstat_recv_recoveryconflict() - - * - * Process a RECOVERYCONFLICT message. - * ---------- - */ -static void -pgstat_recv_recoveryconflict(PgStat_MsgRecoveryConflict *msg, int len) -{ - PgStat_StatDBEntry *dbentry; - - dbentry = pgstat_get_db_entry(msg->m_databaseid, true); - - switch (msg->m_reason) - { - case PROCSIG_RECOVERY_CONFLICT_DATABASE: - - /* - * Since we drop the information about the database as soon as it - * replicates, there is no point in counting these conflicts. - */ - break; - case PROCSIG_RECOVERY_CONFLICT_TABLESPACE: - dbentry->n_conflict_tablespace++; - break; - case PROCSIG_RECOVERY_CONFLICT_LOCK: - dbentry->n_conflict_lock++; - break; - case PROCSIG_RECOVERY_CONFLICT_SNAPSHOT: - dbentry->n_conflict_snapshot++; - break; - case PROCSIG_RECOVERY_CONFLICT_BUFFERPIN: - dbentry->n_conflict_bufferpin++; - break; - case PROCSIG_RECOVERY_CONFLICT_STARTUP_DEADLOCK: - dbentry->n_conflict_startup_deadlock++; - break; - } -} - -/* ---------- - * pgstat_recv_deadlock() - - * - * Process a DEADLOCK message. - * ---------- - */ -static void -pgstat_recv_deadlock(PgStat_MsgDeadlock *msg, int len) -{ - PgStat_StatDBEntry *dbentry; - - dbentry = pgstat_get_db_entry(msg->m_databaseid, true); - - dbentry->n_deadlocks++; -} - -/* ---------- - * pgstat_recv_checksum_failure() - - * - * Process a CHECKSUMFAILURE message. - * ---------- - */ -static void -pgstat_recv_checksum_failure(PgStat_MsgChecksumFailure *msg, int len) -{ - PgStat_StatDBEntry *dbentry; - - dbentry = pgstat_get_db_entry(msg->m_databaseid, true); - - dbentry->n_checksum_failures += msg->m_failurecount; - dbentry->last_checksum_failure = msg->m_failure_time; -} - -/* ---------- - * pgstat_recv_replslot() - - * - * Process a REPLSLOT message. - * ---------- - */ -static void -pgstat_recv_replslot(PgStat_MsgReplSlot *msg, int len) -{ - if (msg->m_drop) - { - Assert(!msg->m_create); - - /* Remove the replication slot statistics with the given name */ - if (replSlotStatHash != NULL) - (void) hash_search(replSlotStatHash, - (void *) &(msg->m_slotname), - HASH_REMOVE, - NULL); - } - else - { - PgStat_StatReplSlotEntry *slotent; - - slotent = pgstat_get_replslot_entry(msg->m_slotname, true); - Assert(slotent); - - if (msg->m_create) - { - /* - * If the message for dropping the slot with the same name gets - * lost, slotent has stats for the old slot. So we initialize all - * counters at slot creation. - */ - pgstat_reset_replslot(slotent, 0); - } - else - { - /* Update the replication slot statistics */ - slotent->spill_txns += msg->m_spill_txns; - slotent->spill_count += msg->m_spill_count; - slotent->spill_bytes += msg->m_spill_bytes; - slotent->stream_txns += msg->m_stream_txns; - slotent->stream_count += msg->m_stream_count; - slotent->stream_bytes += msg->m_stream_bytes; - slotent->total_txns += msg->m_total_txns; - slotent->total_bytes += msg->m_total_bytes; - } - } -} - -/* ---------- - * pgstat_recv_connect() - - * - * Process a CONNECT message. - * ---------- - */ -static void -pgstat_recv_connect(PgStat_MsgConnect *msg, int len) -{ - PgStat_StatDBEntry *dbentry; - - dbentry = pgstat_get_db_entry(msg->m_databaseid, true); - dbentry->n_sessions++; -} - -/* ---------- - * pgstat_recv_disconnect() - - * - * Process a DISCONNECT message. - * ---------- - */ -static void -pgstat_recv_disconnect(PgStat_MsgDisconnect *msg, int len) -{ - PgStat_StatDBEntry *dbentry; - - dbentry = pgstat_get_db_entry(msg->m_databaseid, true); - - switch (msg->m_cause) - { - case DISCONNECT_NOT_YET: - case DISCONNECT_NORMAL: - /* we don't collect these */ - break; - case DISCONNECT_CLIENT_EOF: - dbentry->n_sessions_abandoned++; - break; - case DISCONNECT_FATAL: - dbentry->n_sessions_fatal++; - break; - case DISCONNECT_KILLED: - dbentry->n_sessions_killed++; - break; - } -} - -/* ---------- - * pgstat_recv_tempfile() - - * - * Process a TEMPFILE message. - * ---------- - */ -static void -pgstat_recv_tempfile(PgStat_MsgTempFile *msg, int len) -{ - PgStat_StatDBEntry *dbentry; - - dbentry = pgstat_get_db_entry(msg->m_databaseid, true); - - dbentry->n_temp_bytes += msg->m_filesize; - dbentry->n_temp_files += 1; -} - -/* ---------- - * pgstat_recv_funcstat() - - * - * Count what the backend has done. - * ---------- - */ -static void -pgstat_recv_funcstat(PgStat_MsgFuncstat *msg, int len) -{ - PgStat_FunctionEntry *funcmsg = &(msg->m_entry[0]); - PgStat_StatDBEntry *dbentry; - PgStat_StatFuncEntry *funcentry; - int i; - bool found; - - dbentry = pgstat_get_db_entry(msg->m_databaseid, true); - - /* - * Process all function entries in the message. - */ - for (i = 0; i < msg->m_nentries; i++, funcmsg++) - { - funcentry = (PgStat_StatFuncEntry *) hash_search(dbentry->functions, - (void *) &(funcmsg->f_id), - HASH_ENTER, &found); - - if (!found) - { - /* - * If it's a new function entry, initialize counters to the values - * we just got. - */ - funcentry->f_numcalls = funcmsg->f_numcalls; - funcentry->f_total_time = funcmsg->f_total_time; - funcentry->f_self_time = funcmsg->f_self_time; - } - else - { - /* - * Otherwise add the values to the existing entry. - */ - funcentry->f_numcalls += funcmsg->f_numcalls; - funcentry->f_total_time += funcmsg->f_total_time; - funcentry->f_self_time += funcmsg->f_self_time; - } - } -} - -/* ---------- - * pgstat_recv_funcpurge() - - * - * Arrange for dead function removal. - * ---------- - */ -static void -pgstat_recv_funcpurge(PgStat_MsgFuncpurge *msg, int len) -{ - PgStat_StatDBEntry *dbentry; - int i; - - dbentry = pgstat_get_db_entry(msg->m_databaseid, false); - - /* - * No need to purge if we don't even know the database. - */ - if (!dbentry || !dbentry->functions) - return; - - /* - * Process all function entries in the message. - */ - for (i = 0; i < msg->m_nentries; i++) - { - /* Remove from hashtable if present; we don't care if it's not. */ - (void) hash_search(dbentry->functions, - (void *) &(msg->m_functionid[i]), - HASH_REMOVE, NULL); - } -} - -/* ---------- - * pgstat_write_statsfile_needed() - - * - * Do we need to write out any stats files? - * ---------- - */ -static bool -pgstat_write_statsfile_needed(void) -{ - if (pending_write_requests != NIL) - return true; - - /* Everything was written recently */ - return false; -} - -/* ---------- - * pgstat_db_requested() - - * - * Checks whether stats for a particular DB need to be written to a file. - * ---------- - */ -static bool -pgstat_db_requested(Oid databaseid) -{ - /* - * If any requests are outstanding at all, we should write the stats for - * shared catalogs (the "database" with OID 0). This ensures that - * backends will see up-to-date stats for shared catalogs, even though - * they send inquiry messages mentioning only their own DB. - */ - if (databaseid == InvalidOid && pending_write_requests != NIL) - return true; - - /* Search to see if there's an open request to write this database. */ - if (list_member_oid(pending_write_requests, databaseid)) - return true; - - return false; -} - -/* ---------- - * pgstat_replslot_entry - * - * Return the entry of replication slot stats with the given name. Return - * NULL if not found and the caller didn't request to create it. - * - * create tells whether to create the new slot entry if it is not found. - * ---------- - */ -static PgStat_StatReplSlotEntry * -pgstat_get_replslot_entry(NameData name, bool create) -{ - PgStat_StatReplSlotEntry *slotent; - bool found; - - if (replSlotStatHash == NULL) - { - HASHCTL hash_ctl; - - /* - * Quick return NULL if the hash table is empty and the caller didn't - * request to create the entry. - */ - if (!create) - return NULL; - - hash_ctl.keysize = sizeof(NameData); - hash_ctl.entrysize = sizeof(PgStat_StatReplSlotEntry); - replSlotStatHash = hash_create("Replication slots hash", - PGSTAT_REPLSLOT_HASH_SIZE, - &hash_ctl, - HASH_ELEM | HASH_BLOBS); - } - - slotent = (PgStat_StatReplSlotEntry *) hash_search(replSlotStatHash, - (void *) &name, - create ? HASH_ENTER : HASH_FIND, - &found); - - if (!slotent) - { - /* not found */ - Assert(!create && !found); - return NULL; - } - - /* initialize the entry */ - if (create && !found) - { - namestrcpy(&(slotent->slotname), NameStr(name)); - pgstat_reset_replslot(slotent, 0); - } - - return slotent; -} - -/* ---------- - * pgstat_reset_replslot - * - * Reset the given replication slot stats. - * ---------- - */ -static void -pgstat_reset_replslot(PgStat_StatReplSlotEntry *slotent, TimestampTz ts) -{ - /* reset only counters. Don't clear slot name */ - slotent->spill_txns = 0; - slotent->spill_count = 0; - slotent->spill_bytes = 0; - slotent->stream_txns = 0; - slotent->stream_count = 0; - slotent->stream_bytes = 0; - slotent->total_txns = 0; - slotent->total_bytes = 0; - slotent->stat_reset_timestamp = ts; -} - -/* - * pgstat_slru_index - * - * Determine index of entry for a SLRU with a given name. If there's no exact - * match, returns index of the last "other" entry used for SLRUs defined in - * external projects. - */ -int -pgstat_slru_index(const char *name) -{ - int i; - - for (i = 0; i < SLRU_NUM_ELEMENTS; i++) - { - if (strcmp(slru_names[i], name) == 0) - return i; - } - - /* return index of the last entry (which is the "other" one) */ - return (SLRU_NUM_ELEMENTS - 1); -} - -/* - * pgstat_slru_name - * - * Returns SLRU name for an index. The index may be above SLRU_NUM_ELEMENTS, - * in which case this returns NULL. This allows writing code that does not - * know the number of entries in advance. - */ -const char * -pgstat_slru_name(int slru_idx) -{ - if (slru_idx < 0 || slru_idx >= SLRU_NUM_ELEMENTS) - return NULL; - - return slru_names[slru_idx]; -} - -/* - * slru_entry - * - * Returns pointer to entry with counters for given SLRU (based on the name - * stored in SlruCtl as lwlock tranche name). - */ -static inline PgStat_MsgSLRU * -slru_entry(int slru_idx) -{ - /* - * The postmaster should never register any SLRU statistics counts; if it - * did, the counts would be duplicated into child processes via fork(). - */ - Assert(IsUnderPostmaster || !IsPostmasterEnvironment); - - Assert((slru_idx >= 0) && (slru_idx < SLRU_NUM_ELEMENTS)); - - return &SLRUStats[slru_idx]; -} - -/* - * SLRU statistics count accumulation functions --- called from slru.c - */ - -void -pgstat_count_slru_page_zeroed(int slru_idx) -{ - slru_entry(slru_idx)->m_blocks_zeroed += 1; -} - -void -pgstat_count_slru_page_hit(int slru_idx) -{ - slru_entry(slru_idx)->m_blocks_hit += 1; -} - -void -pgstat_count_slru_page_exists(int slru_idx) -{ - slru_entry(slru_idx)->m_blocks_exists += 1; -} - -void -pgstat_count_slru_page_read(int slru_idx) -{ - slru_entry(slru_idx)->m_blocks_read += 1; -} - -void -pgstat_count_slru_page_written(int slru_idx) -{ - slru_entry(slru_idx)->m_blocks_written += 1; -} - -void -pgstat_count_slru_flush(int slru_idx) -{ - slru_entry(slru_idx)->m_flush += 1; -} - -void -pgstat_count_slru_truncate(int slru_idx) -{ - slru_entry(slru_idx)->m_truncate += 1; -} diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c index f1c3e1f5866..aeffe94a39e 100644 --- a/src/backend/utils/adt/pgstatfuncs.c +++ b/src/backend/utils/adt/pgstatfuncs.c @@ -40,6 +40,12 @@ #include "utils/syscache.h" #include "utils/timestamp.h" +#include "fmgr.h" +#include "cdb/cdbdisp_query.h" +#include "cdb/cdbvars.h" +#include "cdb/cdbdispatchresult.h" +#include "libpq-int.h" + #define UINT32_ACCESS_ONCE(var) ((uint32)(*((volatile uint32 *)&(var)))) #define HAS_PGSTAT_PERMISSIONS(role) (has_privs_of_role(GetUserId(), ROLE_PG_READ_ALL_STATS) || has_privs_of_role(GetUserId(), role)) diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c index b6db630f38a..15130799706 100644 --- a/src/bin/initdb/initdb.c +++ b/src/bin/initdb/initdb.c @@ -192,6 +192,8 @@ static char *external_fts_files; #endif static char *system_functions_file; static char *system_views_file; +static char *system_views_gp_file; +static char *system_views_gp_summary_file; static bool success = false; static bool made_new_pgdata = false; static bool found_existing_pgdata = false; @@ -1204,7 +1206,10 @@ test_config_settings(void) } if (test_specific_config_settings(n_connections, test_buffs)) + { + n_buffers = test_buffs; break; + } } if (i == bufslen) { @@ -1239,7 +1244,7 @@ test_specific_config_settings(int test_conns, int test_buffs) "\"%s\" --check %s %s %s" "-c max_connections=%d " "-c shared_buffers=%d " - "-c dynamic_shared_memory_type=%s" + "-c dynamic_shared_memory_type=%s " "-D %s", backend_exec, boot_options, extra_options, term_fd_opt ? term_fd_opt : "", @@ -1766,8 +1771,6 @@ setup_run_file(FILE *cmdfd, const char *filename) } PG_CMD_PUTS("\n\n"); - - free(lines); } /* @@ -3035,6 +3038,8 @@ setup_data_file_paths(void) set_input(&system_constraints_file, "system_constraints.sql"); set_input(&system_functions_file, "system_functions.sql"); set_input(&system_views_file, "system_views.sql"); + set_input(&system_views_gp_file, "system_views_gp.sql"); + set_input(&system_views_gp_summary_file, "system_views_gp_summary.sql"); set_input(&cdb_init_d_dir, "cdb_init.d"); @@ -3068,6 +3073,8 @@ setup_data_file_paths(void) #endif check_input(system_functions_file); check_input(system_views_file); + check_input(system_views_gp_file); + check_input(system_views_gp_summary_file); } @@ -3397,6 +3404,8 @@ initialize_data_directory(void) */ setup_run_file(cmdfd, system_views_file); + setup_run_file(cmdfd, system_views_gp_file); + setup_run_file(cmdfd, system_views_gp_summary_file); setup_description(cmdfd); diff --git a/src/include/access/nbtree.h b/src/include/access/nbtree.h index bf3b437be73..11c8aaaff8e 100644 --- a/src/include/access/nbtree.h +++ b/src/include/access/nbtree.h @@ -297,7 +297,7 @@ BTPageIsRecyclable(Page page, Relation heaprel) /* Recycling okay iff page is deleted and safexid is old enough */ opaque = BTPageGetOpaque(page); - if (P_ISDELETED(opaque)) + if (RelationIsHeap(heaprel) && P_ISDELETED(opaque)) { FullTransactionId safexid = BTPageGetDeleteXid(page); diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h index 9d989890d21..8ce623c665f 100644 --- a/src/include/commands/vacuum.h +++ b/src/include/commands/vacuum.h @@ -203,19 +203,21 @@ typedef enum VacuumOption VACOPT_PROCESS_MAIN = 1 << 6, /* skip if cannot get lock */ VACOPT_PROCESS_TOAST = 1 << 7, /* process the TOAST table, if any */ VACOPT_DISABLE_PAGE_SKIPPING = 1 << 8, /* don't skip any pages */ + VACOPT_BUFFER_USAGE_LIMIT = 1 << 9, /* vacuum buffer usage limit */ + VACOPT_PARALLEL = 1 << 10, /* parallel vacuum */ /* Extra GPDB options */ - VACOPT_AO_AUX_ONLY = 1 << 9, - VACOPT_ROOTONLY = 1 << 10, - VACOPT_FULLSCAN = 1 << 11, - VACOPT_SKIP_DATABASE_STATS = 1 << 12, - VACOPT_ONLY_DATABASE_STATS = 1 << 13, + VACOPT_AO_AUX_ONLY = 1 << 11, + VACOPT_ROOTONLY = 1 << 12, + VACOPT_FULLSCAN = 1 << 13, + VACOPT_SKIP_DATABASE_STATS = 1 << 14, + VACOPT_ONLY_DATABASE_STATS = 1 << 15, /* AO vacuum phases. Mutually exclusive */ - VACOPT_AO_PRE_CLEANUP_PHASE = 1 << 14, - VACOPT_AO_COMPACT_PHASE = 1 << 15, - VACOPT_AO_POST_CLEANUP_PHASE = 1 << 16, - VACOPT_UPDATE_DATFROZENXID = 1 << 17 + VACOPT_AO_PRE_CLEANUP_PHASE = 1 << 16, + VACOPT_AO_COMPACT_PHASE = 1 << 17, + VACOPT_AO_POST_CLEANUP_PHASE = 1 << 18, + VACOPT_UPDATE_DATFROZENXID = 1 << 19 } VacuumOption; #define VACUUM_AO_PHASE_MASK (VACOPT_AO_PRE_CLEANUP_PHASE | \ @@ -316,6 +318,7 @@ typedef struct VacuumParams * disabled. */ int nworkers; + int buffer_usage_limit; bool auto_stats; /* invoked via automatic statistic collection */ } VacuumParams; diff --git a/src/test/isolation2/expected/analyze_progress.out b/src/test/isolation2/expected/analyze_progress.out new file mode 100644 index 00000000000..68faf24a5e8 --- /dev/null +++ b/src/test/isolation2/expected/analyze_progress.out @@ -0,0 +1,94 @@ +-- Test gp_stat_progress_analyze_summary +-- setup hash distributed table +CREATE TABLE t_analyze_part (a INT, b INT) DISTRIBUTED BY (a); +CREATE +INSERT INTO t_analyze_part SELECT i, i FROM generate_series(1, 100000) i; +INSERT 100000 + +-- Suspend analyze after scanning 20 blocks on each segment +SELECT gp_inject_fault('analyze_block', 'suspend', '', '', '', 20, 20, 0, dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; + gp_inject_fault +----------------- + Success: + Success: + Success: +(3 rows) + +-- session 1: analyze the table +1&: ANALYZE t_analyze_part; +SELECT gp_wait_until_triggered_fault('analyze_block', 1, dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; + gp_wait_until_triggered_fault +------------------------------- + Success: + Success: + Success: +(3 rows) + +-- session 2: query pg_stat_progress_analyze while the analyze is running, the view should indicate 60 blocks have been scanned as aggregated progress of 3 segments +2: SELECT pid IS NOT NULL as has_pid, datname, relid::regclass, phase, sample_blks_total, sample_blks_scanned FROM gp_stat_progress_analyze_summary; + has_pid | datname | relid | phase | sample_blks_total | sample_blks_scanned +---------+----------------+----------------+-----------------------+-------------------+--------------------- + t | isolation2test | t_analyze_part | acquiring sample rows | 111 | 60 +(1 row) + +-- Reset fault injector +SELECT gp_inject_fault('analyze_block', 'reset', dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; + gp_inject_fault +----------------- + Success: + Success: + Success: +(3 rows) +1<: <... completed> +ANALYZE + +-- teardown +DROP TABLE t_analyze_part; +DROP + +-- setup replicated table +CREATE TABLE t_analyze_repl (a INT, b INT) DISTRIBUTED REPLICATED; +CREATE +INSERT INTO t_analyze_repl SELECT i, i FROM generate_series(1, 100000) i; +INSERT 100000 + +-- Suspend analyze after scanning 20 blocks on each segment +SELECT gp_inject_fault('analyze_block', 'suspend', '', '', '', 20, 20, 0, dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; + gp_inject_fault +----------------- + Success: + Success: + Success: +(3 rows) + +-- session 1: analyze the table +1&: ANALYZE t_analyze_repl; +SELECT gp_wait_until_triggered_fault('analyze_block', 1, dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; + gp_wait_until_triggered_fault +------------------------------- + Success: + Success: + Success: +(3 rows) + +-- session 2: query pg_stat_progress_analyze while the analyze is running, the view should indicate 20 blocks have been scanned as average progress of 3 segments +2: SELECT pid IS NOT NULL as has_pid, datname, relid::regclass, phase, sample_blks_total, sample_blks_scanned FROM gp_stat_progress_analyze_summary; + has_pid | datname | relid | phase | sample_blks_total | sample_blks_scanned +---------+----------------+----------------+-----------------------+-------------------+--------------------- + t | isolation2test | t_analyze_repl | acquiring sample rows | 111 | 20 +(1 row) + +-- Reset fault injector +SELECT gp_inject_fault('analyze_block', 'reset', dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; + gp_inject_fault +----------------- + Success: + Success: + Success: +(3 rows) +1<: <... completed> +ANALYZE + +-- teardown +DROP TABLE t_analyze_repl; +DROP diff --git a/src/test/isolation2/expected/ao_index_build_progress.out b/src/test/isolation2/expected/ao_index_build_progress.out index 1048076ce9f..fd91bedfe58 100644 --- a/src/test/isolation2/expected/ao_index_build_progress.out +++ b/src/test/isolation2/expected/ao_index_build_progress.out @@ -8,36 +8,52 @@ CREATE -- Insert all tuples to seg1. INSERT INTO ao_index_build_progress SELECT 0, i FROM generate_series(1, 100000) i; INSERT 100000 +INSERT INTO ao_index_build_progress SELECT 2, i FROM generate_series(1, 100000) i; +INSERT 100000 +INSERT INTO ao_index_build_progress SELECT 5, i FROM generate_series(1, 100000) i; +INSERT 100000 -- Suspend execution when some blocks have been read. -SELECT gp_inject_fault('AppendOnlyStorageRead_ReadNextBlock_success', 'suspend', '', '', '', 10, 10, 0, dbid) FROM gp_segment_configuration WHERE content = 1 AND role = 'p'; +SELECT gp_inject_fault('AppendOnlyStorageRead_ReadNextBlock_success', 'suspend', '', '', '', 10, 10, 0, dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; gp_inject_fault ----------------- Success: -(1 row) + Success: + Success: +(3 rows) 1&: CREATE INDEX ON ao_index_build_progress(i); -- Wait until some AO varblocks have been read. -SELECT gp_wait_until_triggered_fault('AppendOnlyStorageRead_ReadNextBlock_success', 10, dbid) FROM gp_segment_configuration WHERE content = 1 AND role = 'p'; +SELECT gp_wait_until_triggered_fault('AppendOnlyStorageRead_ReadNextBlock_success', 10, dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; gp_wait_until_triggered_fault ------------------------------- Success: -(1 row) + Success: + Success: +(3 rows) -- By now, we should have reported some blocks (of size 'block_size') as "done", -- as well as a total number of blocks that matches the relation's on-disk size. -1U: SELECT command, phase, (pg_relation_size('ao_index_build_progress') + (current_setting('block_size')::int - 1)) / current_setting('block_size')::int AS blocks_total_actual, blocks_total AS blocks_total_reported, blocks_done AS blocks_done_reported FROM pg_stat_progress_create_index WHERE relid = 'ao_index_build_progress'::regclass; +SELECT command, phase, (pg_relation_size('ao_index_build_progress') + (current_setting('block_size')::int - 1)) / current_setting('block_size')::int AS blocks_total_actual, blocks_total AS blocks_total_reported, blocks_done AS blocks_done_reported FROM gp_stat_progress_create_index WHERE gp_segment_id = 1 AND relid = 'ao_index_build_progress'::regclass; command | phase | blocks_total_actual | blocks_total_reported | blocks_done_reported --------------+--------------------------------+---------------------+-----------------------+---------------------- CREATE INDEX | building index: scanning table | 10 | 10 | 2 (1 row) +-- The same should be true for the summary view, and the total number of blocks should be tripled. +SELECT command, phase, blocks_total, blocks_done FROM gp_stat_progress_create_index_summary WHERE relid = 'ao_index_build_progress'::regclass; + command | phase | blocks_total | blocks_done +--------------+--------------------------------+--------------+------------- + CREATE INDEX | building index: scanning table | 30 | 6 +(1 row) -SELECT gp_inject_fault('AppendOnlyStorageRead_ReadNextBlock_success', 'reset', dbid) FROM gp_segment_configuration WHERE content = 1 AND role = 'p'; +SELECT gp_inject_fault('AppendOnlyStorageRead_ReadNextBlock_success', 'reset', dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; gp_inject_fault ----------------- Success: -(1 row) + Success: + Success: +(3 rows) 1<: <... completed> CREATE @@ -49,38 +65,54 @@ CREATE -- Insert all tuples to seg1. INSERT INTO aoco_index_build_progress SELECT 0, i FROM generate_series(1, 100000) i; INSERT 100000 +INSERT INTO aoco_index_build_progress SELECT 2, i FROM generate_series(1, 100000) i; +INSERT 100000 +INSERT INTO aoco_index_build_progress SELECT 5, i FROM generate_series(1, 100000) i; +INSERT 100000 -- Suspend execution when some blocks have been read. -SELECT gp_inject_fault('AppendOnlyStorageRead_ReadNextBlock_success', 'suspend', '', '', '', 5, 5, 0, dbid) FROM gp_segment_configuration WHERE content = 1 AND role = 'p'; +SELECT gp_inject_fault('AppendOnlyStorageRead_ReadNextBlock_success', 'suspend', '', '', '', 5, 5, 0, dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; gp_inject_fault ----------------- Success: -(1 row) + Success: + Success: +(3 rows) 1&: CREATE INDEX ON aoco_index_build_progress(i); -- Wait until some AOCO varblocks have been read. -SELECT gp_wait_until_triggered_fault('AppendOnlyStorageRead_ReadNextBlock_success', 5, dbid) FROM gp_segment_configuration WHERE content = 1 AND role = 'p'; +SELECT gp_wait_until_triggered_fault('AppendOnlyStorageRead_ReadNextBlock_success', 5, dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; gp_wait_until_triggered_fault ------------------------------- Success: -(1 row) + Success: + Success: +(3 rows) -- By now, we should have reported some blocks (of size 'block_size') as "done", -- as well as a total number of blocks that matches the relation's on-disk size. -- Note: all blocks for the relation have to be scanned as we are building an -- index for the first time and a block directory has to be created. -1U: SELECT command, phase, (pg_relation_size('aoco_index_build_progress') + (current_setting('block_size')::int - 1)) / current_setting('block_size')::int AS blocks_total_actual, blocks_total AS blocks_total_reported, blocks_done AS blocks_done_reported FROM pg_stat_progress_create_index WHERE relid = 'aoco_index_build_progress'::regclass; +SELECT command, phase, (pg_relation_size('aoco_index_build_progress') + (current_setting('block_size')::int - 1)) / current_setting('block_size')::int AS blocks_total_actual, blocks_total AS blocks_total_reported, blocks_done AS blocks_done_reported FROM gp_stat_progress_create_index WHERE gp_segment_id = 1 AND relid = 'aoco_index_build_progress'::regclass; command | phase | blocks_total_actual | blocks_total_reported | blocks_done_reported --------------+--------------------------------+---------------------+-----------------------+---------------------- CREATE INDEX | building index: scanning table | 20 | 20 | 4 (1 row) +-- The same should be true for the summary view, and the total number of blocks should be tripled. +SELECT command, phase, blocks_total, blocks_done FROM gp_stat_progress_create_index_summary WHERE relid = 'aoco_index_build_progress'::regclass; + command | phase | blocks_total | blocks_done +--------------+--------------------------------+--------------+------------- + CREATE INDEX | building index: scanning table | 60 | 12 +(1 row) -SELECT gp_inject_fault('AppendOnlyStorageRead_ReadNextBlock_success', 'reset', dbid) FROM gp_segment_configuration WHERE content = 1 AND role = 'p'; +SELECT gp_inject_fault('AppendOnlyStorageRead_ReadNextBlock_success', 'reset', dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; gp_inject_fault ----------------- Success: -(1 row) + Success: + Success: +(3 rows) 1<: <... completed> CREATE @@ -88,36 +120,48 @@ CREATE -- Repeat the test for another index build -- Suspend execution when some blocks have been read. -SELECT gp_inject_fault('AppendOnlyStorageRead_ReadNextBlock_success', 'suspend', '', '', '', 5, 5, 0, dbid) FROM gp_segment_configuration WHERE content = 1 AND role = 'p'; +SELECT gp_inject_fault('AppendOnlyStorageRead_ReadNextBlock_success', 'suspend', '', '', '', 5, 5, 0, dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; gp_inject_fault ----------------- Success: -(1 row) + Success: + Success: +(3 rows) 1&: CREATE INDEX ON aoco_index_build_progress(j); -- Wait until some AOCO varblocks have been read. -SELECT gp_wait_until_triggered_fault('AppendOnlyStorageRead_ReadNextBlock_success', 5, dbid) FROM gp_segment_configuration WHERE content = 1 AND role = 'p'; +SELECT gp_wait_until_triggered_fault('AppendOnlyStorageRead_ReadNextBlock_success', 5, dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; gp_wait_until_triggered_fault ------------------------------- Success: -(1 row) + Success: + Success: +(3 rows) -- By now, we should have reported some blocks (of size 'block_size') as "done", -- as well as a total number of blocks that matches the size of col j's segfile. -- Note: since we already had a block directory prior to the index build on -- column 'j', only column 'j' will be scanned. CBDB_CHERRY_PICK_MERGE_FIXME: fix when ao blkdir will be supported -1U: SELECT command, phase, ((pg_stat_file(pg_relation_filepath('aoco_index_build_progress') || '.' || 129)).size + (current_setting('block_size')::int - 1)) / current_setting('block_size')::int AS col_j_blocks, blocks_total AS blocks_total_reported, blocks_done AS blocks_done_reported FROM pg_stat_progress_create_index WHERE relid = 'aoco_index_build_progress'::regclass; +1U: SELECT command, phase, ((pg_stat_file(pg_relation_filepath('aoco_index_build_progress') || '.' || 129)).size + (current_setting('block_size')::int - 1)) / current_setting('block_size')::int AS col_j_blocks, blocks_total AS blocks_total_reported, blocks_done AS blocks_done_reported FROM gp_stat_progress_create_index WHERE gp_segment_id = 1 AND relid = 'aoco_index_build_progress'::regclass; command | phase | col_j_blocks | blocks_total_reported | blocks_done_reported --------------+--------------------------------+--------------+-----------------------+---------------------- CREATE INDEX | building index: scanning table | 8 | 20 | 4 (1 row) +-- The same should be true for the summary view, and the total number of blocks should be tripled. +SELECT command, phase, blocks_total, blocks_done FROM gp_stat_progress_create_index_summary WHERE relid = 'aoco_index_build_progress'::regclass; + command | phase | blocks_total | blocks_done +--------------+--------------------------------+--------------+------------- + CREATE INDEX | building index: scanning table | 60 | 12 +(1 row) -SELECT gp_inject_fault('AppendOnlyStorageRead_ReadNextBlock_success', 'reset', dbid) FROM gp_segment_configuration WHERE content = 1 AND role = 'p'; +SELECT gp_inject_fault('AppendOnlyStorageRead_ReadNextBlock_success', 'reset', dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; gp_inject_fault ----------------- Success: -(1 row) + Success: + Success: +(3 rows) 1<: <... completed> CREATE diff --git a/src/test/isolation2/expected/vacuum_progress_column.out b/src/test/isolation2/expected/vacuum_progress_column.out index 587bd35f7c8..2889f8a9256 100644 --- a/src/test/isolation2/expected/vacuum_progress_column.out +++ b/src/test/isolation2/expected/vacuum_progress_column.out @@ -45,18 +45,6 @@ ABORT DELETE FROM vacuum_progress_ao_column where j % 2 = 0; DELETE 50000 --- Lookup pg_class and collected stats view before VACUUM -SELECT relpages, reltuples, relallvisible FROM pg_class where relname = 'vacuum_progress_ao_column'; - relpages | reltuples | relallvisible -----------+-----------+--------------- - 0 | -1 | 0 -(1 row) -SELECT n_live_tup, n_dead_tup, last_vacuum, vacuum_count FROM pg_stat_all_tables WHERE relname = 'vacuum_progress_ao_column'; - n_live_tup | n_dead_tup | last_vacuum | vacuum_count -------------+------------+-------------+-------------- - 100000 | 200000 | | 0 -(1 row) - -- Perform VACUUM and observe the progress -- Suspend execution at pre-cleanup phase after truncating both segfiles to their logical EOF. @@ -168,7 +156,7 @@ SELECT relpages, reltuples, relallvisible FROM pg_class where relname = 'vacuum_ ----------+-----------+--------------- 37 | 50000 | 0 (1 row) -SELECT n_live_tup, n_dead_tup, last_vacuum is not null as has_last_vacuum, vacuum_count FROM pg_stat_all_tables WHERE relname = 'vacuum_progress_ao_column'; +SELECT n_live_tup, n_dead_tup, last_vacuum is not null as has_last_vacuum, vacuum_count FROM gp_stat_all_tables WHERE relname = 'vacuum_progress_ao_column' and gp_segment_id = 1; n_live_tup | n_dead_tup | has_last_vacuum | vacuum_count ------------+------------+-----------------+-------------- 50000 | 0 | t | 1 @@ -248,7 +236,7 @@ SELECT relpages, reltuples, relallvisible FROM pg_class where relname = 'vacuum_ ----------+-----------+--------------- 13 | 50000 | 0 (1 row) -SELECT n_live_tup, n_dead_tup, last_vacuum is not null as has_last_vacuum, vacuum_count FROM pg_stat_all_tables WHERE relname = 'vacuum_progress_ao_column'; +SELECT n_live_tup, n_dead_tup, last_vacuum is not null as has_last_vacuum, vacuum_count FROM gp_stat_all_tables WHERE relname = 'vacuum_progress_ao_column' and gp_segment_id = 1; n_live_tup | n_dead_tup | has_last_vacuum | vacuum_count ------------+------------+-----------------+-------------- 50000 | 0 | t | 2 @@ -259,19 +247,6 @@ SELECT n_live_tup, n_dead_tup, last_vacuum is not null as has_last_vacuum, vacuu -- Current behavior is it will clear previous compact phase num_dead_tuples in post-cleanup -- phase (at injecting point vacuum_ao_post_cleanup_end), which is different from above case -- in which vacuum worker isn't changed. -ALTER SYSTEM SET gp_fts_mark_mirror_down_grace_period to 10; -ALTER -ALTER SYSTEM SET gp_fts_probe_interval to 10; -ALTER -SELECT gp_segment_id, pg_reload_conf() FROM gp_id UNION SELECT gp_segment_id, pg_reload_conf() FROM gp_dist_random('gp_id'); - gp_segment_id | pg_reload_conf ----------------+---------------- - 2 | t - 1 | t - 0 | t - -1 | t -(4 rows) - DROP TABLE IF EXISTS vacuum_progress_ao_column; DROP CREATE TABLE vacuum_progress_ao_column(i int, j int); @@ -315,7 +290,7 @@ DELETE 50000 SET 1&: vacuum vacuum_progress_ao_column; -2: SELECT gp_wait_until_triggered_fault('vacuum_ao_after_compact', 3, dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; +2: SELECT gp_wait_until_triggered_fault('vacuum_ao_after_compact', 1, dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; gp_wait_until_triggered_fault ------------------------------- Success: @@ -325,13 +300,17 @@ SET -- Non-zero progressing data num_dead_tuples is showed up. select gp_segment_id, relid::regclass as relname, phase, heap_blks_total, heap_blks_scanned, heap_blks_vacuumed, index_vacuum_count, max_dead_tuples, num_dead_tuples from gp_stat_progress_vacuum where gp_segment_id > -1; -ERROR: relation "gp_stat_progress_vacuum" does not exist -LINE 1: ...cuum_count, max_dead_tuples, num_dead_tuples from gp_stat_pr... - ^ + gp_segment_id | relname | phase | heap_blks_total | heap_blks_scanned | heap_blks_vacuumed | index_vacuum_count | max_dead_tuples | num_dead_tuples +---------------+---------------------------+--------------------------+-----------------+-------------------+--------------------+--------------------+-----------------+----------------- + 1 | vacuum_progress_ao_column | append-optimized compact | 25 | 9 | 17 | 0 | 33327 | 16621 + 0 | vacuum_progress_ao_column | append-optimized compact | 25 | 9 | 17 | 0 | 33462 | 16726 + 2 | vacuum_progress_ao_column | append-optimized compact | 25 | 9 | 17 | 0 | 33211 | 16653 +(3 rows) select relid::regclass as relname, phase, heap_blks_total, heap_blks_scanned, heap_blks_vacuumed, index_vacuum_count, max_dead_tuples, num_dead_tuples from gp_stat_progress_vacuum_summary; -ERROR: relation "gp_stat_progress_vacuum_summary" does not exist -LINE 1: ...cuum_count, max_dead_tuples, num_dead_tuples from gp_stat_pr... - ^ + relname | phase | heap_blks_total | heap_blks_scanned | heap_blks_vacuumed | index_vacuum_count | max_dead_tuples | num_dead_tuples +---------------------------+--------------------------+-----------------+-------------------+--------------------+--------------------+-----------------+----------------- + vacuum_progress_ao_column | append-optimized compact | 75 | 27 | 51 | 0 | 100000 | 50000 +(1 row) -- Resume execution of compact phase and block at syncrep on one segment. 2: SELECT gp_inject_fault_infinite('wal_sender_loop', 'suspend', dbid) FROM gp_segment_configuration WHERE role = 'p' and content = 1; @@ -372,7 +351,7 @@ LINE 1: ...cuum_count, max_dead_tuples, num_dead_tuples from gp_stat_pr... -- initializes a new vacrelstats at the beginning of post-cleanup phase. -- Also all segments should reach to the same "vacuum_worker_changed" point -- due to FTS version being changed. -2: SELECT gp_wait_until_triggered_fault('vacuum_worker_changed', 3, dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; +2: SELECT gp_wait_until_triggered_fault('vacuum_worker_changed', 1, dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; gp_wait_until_triggered_fault ------------------------------- Success: @@ -383,10 +362,10 @@ LINE 1: ...cuum_count, max_dead_tuples, num_dead_tuples from gp_stat_pr... 2: SELECT content, role, preferred_role, mode, status FROM gp_segment_configuration WHERE content > -1; content | role | preferred_role | mode | status ---------+------+----------------+------+-------- - 0 | p | p | s | u - 0 | m | m | s | u 2 | p | p | s | u 2 | m | m | s | u + 0 | p | p | s | u + 0 | m | m | s | u 1 | p | p | n | u 1 | m | m | n | d (6 rows) @@ -406,7 +385,7 @@ LINE 1: ...cuum_count, max_dead_tuples, num_dead_tuples from gp_stat_pr... Success: Success: (3 rows) -2: SELECT gp_wait_until_triggered_fault('vacuum_ao_post_cleanup_end', 3, dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; +2: SELECT gp_wait_until_triggered_fault('vacuum_ao_post_cleanup_end', 1, dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; gp_wait_until_triggered_fault ------------------------------- Success: @@ -416,13 +395,17 @@ LINE 1: ...cuum_count, max_dead_tuples, num_dead_tuples from gp_stat_pr... -- The previous collected num_dead_tuples in compact phase is zero. select gp_segment_id, relid::regclass as relname, phase, heap_blks_total, heap_blks_scanned, heap_blks_vacuumed, index_vacuum_count, max_dead_tuples, num_dead_tuples from gp_stat_progress_vacuum where gp_segment_id > -1; -ERROR: relation "gp_stat_progress_vacuum" does not exist -LINE 1: ...cuum_count, max_dead_tuples, num_dead_tuples from gp_stat_pr... - ^ + gp_segment_id | relname | phase | heap_blks_total | heap_blks_scanned | heap_blks_vacuumed | index_vacuum_count | max_dead_tuples | num_dead_tuples +---------------+---------------------------+-------------------------------+-----------------+-------------------+--------------------+--------------------+-----------------+----------------- + 2 | vacuum_progress_ao_column | append-optimized post-cleanup | 0 | 0 | 0 | 0 | 0 | 0 + 0 | vacuum_progress_ao_column | append-optimized post-cleanup | 0 | 0 | 0 | 0 | 0 | 0 + 1 | vacuum_progress_ao_column | append-optimized post-cleanup | 0 | 0 | 0 | 0 | 0 | 0 +(3 rows) select relid::regclass as relname, phase, heap_blks_total, heap_blks_scanned, heap_blks_vacuumed, index_vacuum_count, max_dead_tuples, num_dead_tuples from gp_stat_progress_vacuum_summary; -ERROR: relation "gp_stat_progress_vacuum_summary" does not exist -LINE 1: ...cuum_count, max_dead_tuples, num_dead_tuples from gp_stat_pr... - ^ + relname | phase | heap_blks_total | heap_blks_scanned | heap_blks_vacuumed | index_vacuum_count | max_dead_tuples | num_dead_tuples +---------------------------+-------------------------------+-----------------+-------------------+--------------------+--------------------+-----------------+----------------- + vacuum_progress_ao_column | append-optimized post-cleanup | 0 | 0 | 0 | 0 | 0 | 0 +(1 row) 2: SELECT gp_inject_fault('vacuum_ao_post_cleanup_end', 'reset', dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; gp_inject_fault @@ -469,15 +452,3 @@ reset Debug_appendonly_print_compaction; RESET reset default_table_access_method; RESET -ALTER SYSTEM RESET gp_fts_mark_mirror_down_grace_period; -ALTER -ALTER SYSTEM RESET gp_fts_probe_interval; -ALTER -SELECT gp_segment_id, pg_reload_conf() FROM gp_id UNION SELECT gp_segment_id, pg_reload_conf() FROM gp_dist_random('gp_id'); - gp_segment_id | pg_reload_conf ----------------+---------------- - 2 | t - 1 | t - 0 | t - -1 | t -(4 rows) diff --git a/src/test/isolation2/expected/vacuum_progress_row.out b/src/test/isolation2/expected/vacuum_progress_row.out index 0f1b3e65ef5..81392c5a9ef 100644 --- a/src/test/isolation2/expected/vacuum_progress_row.out +++ b/src/test/isolation2/expected/vacuum_progress_row.out @@ -16,22 +16,21 @@ CREATE CREATE INDEX on vacuum_progress_ao_row(j); CREATE --- Insert all tuples to seg1 from two current sessions so that data are stored --- in two segment files. +-- Insert from two current sessions so that data are stored in two segment files. 1: BEGIN; BEGIN 2: BEGIN; BEGIN -1: INSERT INTO vacuum_progress_ao_row SELECT 0, i FROM generate_series(1, 100000) i; +1: INSERT INTO vacuum_progress_ao_row SELECT i, i FROM generate_series(1, 100000) i; INSERT 100000 -2: INSERT INTO vacuum_progress_ao_row SELECT 0, i FROM generate_series(1, 100000) i; +2: INSERT INTO vacuum_progress_ao_row SELECT i, i FROM generate_series(1, 100000) i; INSERT 100000 -- Commit so that the logical EOF of segno 2 is non-zero. 2: COMMIT; COMMIT 2: BEGIN; BEGIN -2: INSERT INTO vacuum_progress_ao_row SELECT 0, i FROM generate_series(1, 100000) i; +2: INSERT INTO vacuum_progress_ao_row SELECT i, i FROM generate_series(1, 100000) i; INSERT 100000 -- Abort so that segno 2 has dead tuples after its logical EOF 2: ABORT; @@ -45,26 +44,16 @@ ABORT DELETE FROM vacuum_progress_ao_row where j % 2 = 0; DELETE 50000 --- Lookup pg_class and collected stats view before VACUUM -SELECT relpages, reltuples, relallvisible FROM pg_class where relname = 'vacuum_progress_ao_row'; - relpages | reltuples | relallvisible -----------+-----------+--------------- - 0 | -1 | 0 -(1 row) -SELECT n_live_tup, n_dead_tup, last_vacuum, vacuum_count FROM pg_stat_all_tables WHERE relname = 'vacuum_progress_ao_row'; - n_live_tup | n_dead_tup | last_vacuum | vacuum_count -------------+------------+-------------+-------------- - 100000 | 200000 | | 0 -(1 row) - -- Perform VACUUM and observe the progress -- Suspend execution at pre-cleanup phase after truncating both segfiles to their logical EOF. -SELECT gp_inject_fault('appendonly_after_truncate_segment_file', 'suspend', '', '', '', 2, 2, 0, dbid) FROM gp_segment_configuration WHERE content = 1 AND role = 'p'; +SELECT gp_inject_fault('appendonly_after_truncate_segment_file', 'suspend', '', '', '', 2, 2, 0, dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; gp_inject_fault ----------------- Success: -(1 row) + Success: + Success: +(3 rows) 1: set Debug_appendonly_print_compaction to on; SET @@ -75,85 +64,124 @@ SELECT gp_wait_until_triggered_fault('appendonly_after_truncate_segment_file', 2 Success: (1 row) -- We are in pre_cleanup phase and some blocks should've been vacuumed by now -1U: select relid::regclass as relname, phase, heap_blks_total, heap_blks_scanned, heap_blks_vacuumed, index_vacuum_count, max_dead_tuples, num_dead_tuples from pg_stat_progress_vacuum; +select relid::regclass as relname, phase, heap_blks_total, heap_blks_scanned, heap_blks_vacuumed, index_vacuum_count, max_dead_tuples, num_dead_tuples from gp_stat_progress_vacuum where gp_segment_id = 1; + relname | phase | heap_blks_total | heap_blks_scanned | heap_blks_vacuumed | index_vacuum_count | max_dead_tuples | num_dead_tuples +------------------------+------------------------------+-----------------+-------------------+--------------------+--------------------+-----------------+----------------- + vacuum_progress_ao_row | append-optimized pre-cleanup | 55 | 0 | 37 | 0 | 33327 | 0 +(1 row) +select relid::regclass as relname, phase, heap_blks_total, heap_blks_scanned, heap_blks_vacuumed, index_vacuum_count, max_dead_tuples, num_dead_tuples from gp_stat_progress_vacuum_summary; relname | phase | heap_blks_total | heap_blks_scanned | heap_blks_vacuumed | index_vacuum_count | max_dead_tuples | num_dead_tuples ------------------------+------------------------------+-----------------+-------------------+--------------------+--------------------+-----------------+----------------- - vacuum_progress_ao_row | append-optimized pre-cleanup | 165 | 0 | 110 | 0 | 100000 | 0 + vacuum_progress_ao_row | append-optimized pre-cleanup | 166 | 0 | 111 | 0 | 100000 | 0 (1 row) -- Resume execution and suspend again in the middle of compact phase -SELECT gp_inject_fault('appendonly_insert', 'suspend', '', '', '', 200, 200, 0, dbid) FROM gp_segment_configuration WHERE content = 1 AND role = 'p'; +SELECT gp_inject_fault('appendonly_insert', 'suspend', '', '', '', 200, 200, 0, dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; gp_inject_fault ----------------- Success: -(1 row) -SELECT gp_inject_fault('appendonly_after_truncate_segment_file', 'reset', dbid) FROM gp_segment_configuration WHERE content = 1 AND role = 'p'; + Success: + Success: +(3 rows) +SELECT gp_inject_fault('appendonly_after_truncate_segment_file', 'reset', dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; gp_inject_fault ----------------- Success: -(1 row) + Success: + Success: +(3 rows) SELECT gp_wait_until_triggered_fault('appendonly_insert', 200, dbid) FROM gp_segment_configuration WHERE content = 1 AND role = 'p'; gp_wait_until_triggered_fault ------------------------------- Success: (1 row) -- We are in compact phase. num_dead_tuples should increase as we move and count tuples, one by one. -1U: select relid::regclass as relname, phase, heap_blks_total, heap_blks_scanned, heap_blks_vacuumed, index_vacuum_count, max_dead_tuples, num_dead_tuples from pg_stat_progress_vacuum; +select relid::regclass as relname, phase, heap_blks_total, heap_blks_scanned, heap_blks_vacuumed, index_vacuum_count, max_dead_tuples, num_dead_tuples from gp_stat_progress_vacuum where gp_segment_id = 1; relname | phase | heap_blks_total | heap_blks_scanned | heap_blks_vacuumed | index_vacuum_count | max_dead_tuples | num_dead_tuples ------------------------+--------------------------+-----------------+-------------------+--------------------+--------------------+-----------------+----------------- - vacuum_progress_ao_row | append-optimized compact | 165 | 0 | 110 | 0 | 100000 | 199 + vacuum_progress_ao_row | append-optimized compact | 55 | 0 | 37 | 0 | 33327 | 227 +(1 row) +select relid::regclass as relname, phase, heap_blks_total, heap_blks_scanned, heap_blks_vacuumed, index_vacuum_count, max_dead_tuples, num_dead_tuples from gp_stat_progress_vacuum_summary; + relname | phase | heap_blks_total | heap_blks_scanned | heap_blks_vacuumed | index_vacuum_count | max_dead_tuples | num_dead_tuples +------------------------+--------------------------+-----------------+-------------------+--------------------+--------------------+-----------------+----------------- + vacuum_progress_ao_row | append-optimized compact | 166 | 0 | 111 | 0 | 100000 | 594 (1 row) -- Resume execution and suspend again after compacting all segfiles -SELECT gp_inject_fault('vacuum_ao_after_compact', 'suspend', dbid) FROM gp_segment_configuration WHERE content = 1 AND role = 'p'; +SELECT gp_inject_fault('vacuum_ao_after_compact', 'suspend', dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; gp_inject_fault ----------------- Success: -(1 row) -SELECT gp_inject_fault('appendonly_insert', 'reset', dbid) FROM gp_segment_configuration WHERE content = 1 AND role = 'p'; + Success: + Success: +(3 rows) +SELECT gp_inject_fault('appendonly_insert', 'reset', dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; gp_inject_fault ----------------- Success: -(1 row) -SELECT gp_wait_until_triggered_fault('vacuum_ao_after_compact', 1, dbid) FROM gp_segment_configuration WHERE content = 1 AND role = 'p'; + Success: + Success: +(3 rows) +SELECT gp_wait_until_triggered_fault('vacuum_ao_after_compact', 1, dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; gp_wait_until_triggered_fault ------------------------------- Success: -(1 row) + Success: + Success: +(3 rows) -- After compacting all segfiles we expect 50000 dead tuples -1U: select relid::regclass as relname, phase, heap_blks_total, heap_blks_scanned, heap_blks_vacuumed, index_vacuum_count, max_dead_tuples, num_dead_tuples from pg_stat_progress_vacuum; +select relid::regclass as relname, phase, heap_blks_total, heap_blks_scanned, heap_blks_vacuumed, index_vacuum_count, max_dead_tuples, num_dead_tuples from gp_stat_progress_vacuum where gp_segment_id = 1; + relname | phase | heap_blks_total | heap_blks_scanned | heap_blks_vacuumed | index_vacuum_count | max_dead_tuples | num_dead_tuples +------------------------+--------------------------+-----------------+-------------------+--------------------+--------------------+-----------------+----------------- + vacuum_progress_ao_row | append-optimized compact | 55 | 19 | 37 | 0 | 33327 | 16622 +(1 row) +select relid::regclass as relname, phase, heap_blks_total, heap_blks_scanned, heap_blks_vacuumed, index_vacuum_count, max_dead_tuples, num_dead_tuples from gp_stat_progress_vacuum_summary; relname | phase | heap_blks_total | heap_blks_scanned | heap_blks_vacuumed | index_vacuum_count | max_dead_tuples | num_dead_tuples ------------------------+--------------------------+-----------------+-------------------+--------------------+--------------------+-----------------+----------------- - vacuum_progress_ao_row | append-optimized compact | 165 | 55 | 110 | 0 | 100000 | 50000 + vacuum_progress_ao_row | append-optimized compact | 166 | 57 | 111 | 0 | 100000 | 50000 (1 row) -- Resume execution and entering post_cleaup phase, suspend at the end of it. -SELECT gp_inject_fault('vacuum_ao_post_cleanup_end', 'suspend', dbid) FROM gp_segment_configuration WHERE content = 1 AND role = 'p'; +SELECT gp_inject_fault('vacuum_ao_post_cleanup_end', 'suspend', dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; gp_inject_fault ----------------- Success: -(1 row) -SELECT gp_inject_fault('vacuum_ao_after_compact', 'reset', dbid) FROM gp_segment_configuration WHERE content = 1 AND role = 'p'; + Success: + Success: +(3 rows) +SELECT gp_inject_fault('vacuum_ao_after_compact', 'reset', dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; gp_inject_fault ----------------- Success: -(1 row) -SELECT gp_wait_until_triggered_fault('vacuum_ao_post_cleanup_end', 1, dbid) FROM gp_segment_configuration WHERE content = 1 AND role = 'p'; + Success: + Success: +(3 rows) +SELECT gp_wait_until_triggered_fault('vacuum_ao_post_cleanup_end', 1, dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; gp_wait_until_triggered_fault ------------------------------- Success: -(1 row) + Success: + Success: +(3 rows) -- We should have skipped recycling the awaiting drop segment because the segment was still visible to the SELECT gp_wait_until_triggered_fault query. -1U: select relid::regclass as relname, phase, heap_blks_total, heap_blks_scanned, heap_blks_vacuumed, index_vacuum_count, max_dead_tuples, num_dead_tuples from pg_stat_progress_vacuum; +select relid::regclass as relname, phase, heap_blks_total, heap_blks_scanned, heap_blks_vacuumed, index_vacuum_count, max_dead_tuples, num_dead_tuples from gp_stat_progress_vacuum where gp_segment_id = 1; relname | phase | heap_blks_total | heap_blks_scanned | heap_blks_vacuumed | index_vacuum_count | max_dead_tuples | num_dead_tuples ------------------------+-------------------------------+-----------------+-------------------+--------------------+--------------------+-----------------+----------------- - vacuum_progress_ao_row | append-optimized post-cleanup | 165 | 55 | 110 | 0 | 100000 | 50000 + vacuum_progress_ao_row | append-optimized post-cleanup | 55 | 19 | 37 | 0 | 33327 | 16622 (1 row) -SELECT gp_inject_fault('vacuum_ao_post_cleanup_end', 'reset', dbid) FROM gp_segment_configuration WHERE content = 1 AND role = 'p'; +select relid::regclass as relname, phase, heap_blks_total, heap_blks_scanned, heap_blks_vacuumed, index_vacuum_count, max_dead_tuples, num_dead_tuples from gp_stat_progress_vacuum_summary; + relname | phase | heap_blks_total | heap_blks_scanned | heap_blks_vacuumed | index_vacuum_count | max_dead_tuples | num_dead_tuples +------------------------+-------------------------------+-----------------+-------------------+--------------------+--------------------+-----------------+----------------- + vacuum_progress_ao_row | append-optimized post-cleanup | 166 | 57 | 111 | 0 | 100000 | 50000 +(1 row) + +SELECT gp_inject_fault('vacuum_ao_post_cleanup_end', 'reset', dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; gp_inject_fault ----------------- Success: -(1 row) + Success: + Success: +(3 rows) 1<: <... completed> VACUUM @@ -166,63 +194,68 @@ VACUUM SELECT relpages, reltuples, relallvisible FROM pg_class where relname = 'vacuum_progress_ao_row'; relpages | reltuples | relallvisible ----------+-----------+--------------- - 83 | 50000 | 0 + 84 | 50000 | 0 (1 row) -SELECT n_live_tup, n_dead_tup, last_vacuum is not null as has_last_vacuum, vacuum_count FROM pg_stat_all_tables WHERE relname = 'vacuum_progress_ao_row'; +SELECT n_live_tup, n_dead_tup, last_vacuum is not null as has_last_vacuum, vacuum_count FROM gp_stat_all_tables WHERE relname = 'vacuum_progress_ao_row' and gp_segment_id = 1; n_live_tup | n_dead_tup | has_last_vacuum | vacuum_count ------------+------------+-----------------+-------------- - 50000 | 0 | t | 1 + 16705 | 0 | t | 1 (1 row) -- Perform VACUUM again to recycle the remaining awaiting drop segment marked by the previous run. -SELECT gp_inject_fault('vacuum_ao_after_index_delete', 'suspend', dbid) FROM gp_segment_configuration WHERE content = 1 AND role = 'p'; +SELECT gp_inject_fault('vacuum_ao_after_index_delete', 'suspend', dbid) FROM gp_segment_configuration WHERE content = 0 AND role = 'p'; gp_inject_fault ----------------- Success: (1 row) -1&: VACUUM vacuum_progress_ao_row; --- Resume execution and entering pre_cleanup phase, suspend at vacuuming indexes. -SELECT gp_inject_fault('vacuum_ao_after_compact', 'reset', dbid) FROM gp_segment_configuration WHERE content = 1 AND role = 'p'; +SELECT gp_inject_fault('appendonly_after_truncate_segment_file', 'suspend', dbid) FROM gp_segment_configuration WHERE content > 0 AND role = 'p'; gp_inject_fault ----------------- Success: -(1 row) -SELECT gp_wait_until_triggered_fault('vacuum_ao_after_index_delete', 1, dbid) FROM gp_segment_configuration WHERE content = 1 AND role = 'p'; + Success: +(2 rows) +1&: VACUUM vacuum_progress_ao_row; +-- Resume execution and entering pre_cleanup phase, suspend at vacuuming indexes for segment 0. +SELECT gp_wait_until_triggered_fault('vacuum_ao_after_index_delete', 1, dbid) FROM gp_segment_configuration WHERE content = 0 AND role = 'p'; gp_wait_until_triggered_fault ------------------------------- Success: (1 row) --- We are in vacuuming indexes phase (part of ao pre_cleanup phase), index_vacuum_count should increase to 1. -1U: select relid::regclass as relname, phase, heap_blks_total, heap_blks_scanned, heap_blks_vacuumed, index_vacuum_count, max_dead_tuples, num_dead_tuples from pg_stat_progress_vacuum; +-- Resume execution and moving on to truncate segments that were marked as AWAITING_DROP for segment 1 and 2, there should be only 1. +SELECT gp_wait_until_triggered_fault('appendonly_after_truncate_segment_file', 1, dbid) FROM gp_segment_configuration WHERE content > 0 AND role = 'p'; + gp_wait_until_triggered_fault +------------------------------- + Success: + Success: +(2 rows) +-- Segment 0 is in vacuuming indexes phase (part of ao pre_cleanup phase), index_vacuum_count should increase to 1. +select relid::regclass as relname, phase, heap_blks_total, heap_blks_scanned, heap_blks_vacuumed, index_vacuum_count, max_dead_tuples, num_dead_tuples from gp_stat_progress_vacuum where gp_segment_id = 0; relname | phase | heap_blks_total | heap_blks_scanned | heap_blks_vacuumed | index_vacuum_count | max_dead_tuples | num_dead_tuples ------------------------+-------------------+-----------------+-------------------+--------------------+--------------------+-----------------+----------------- - vacuum_progress_ao_row | vacuuming indexes | 83 | 0 | 0 | 1 | 50000 | 0 + vacuum_progress_ao_row | vacuuming indexes | 28 | 0 | 0 | 1 | 16737 | 0 (1 row) +-- Segment 1 and 2 are in truncate segments phase (part of ao post_cleanup phase), heap_blks_vacuumed should increase to 1. +select relid::regclass as relname, phase, heap_blks_total, heap_blks_scanned, heap_blks_vacuumed, index_vacuum_count, max_dead_tuples, num_dead_tuples from gp_stat_progress_vacuum where gp_segment_id > 0; + relname | phase | heap_blks_total | heap_blks_scanned | heap_blks_vacuumed | index_vacuum_count | max_dead_tuples | num_dead_tuples +------------------------+------------------------------+-----------------+-------------------+--------------------+--------------------+-----------------+----------------- + vacuum_progress_ao_row | append-optimized pre-cleanup | 28 | 0 | 19 | 2 | 16558 | 0 + vacuum_progress_ao_row | append-optimized pre-cleanup | 28 | 0 | 19 | 2 | 16705 | 0 +(2 rows) +select relid::regclass as relname, phase, heap_blks_total, heap_blks_scanned, heap_blks_vacuumed, index_vacuum_count, max_dead_tuples, num_dead_tuples from gp_stat_progress_vacuum_summary; + relname | phase | heap_blks_total | heap_blks_scanned | heap_blks_vacuumed | index_vacuum_count | max_dead_tuples | num_dead_tuples +------------------------+------------------------------+-----------------+-------------------+--------------------+--------------------+-----------------+----------------- + vacuum_progress_ao_row | append-optimized pre-cleanup | 56 | 0 | 38 | 4 | 33263 | 0 + vacuum_progress_ao_row | vacuuming indexes | 28 | 0 | 0 | 1 | 16737 | 0 +(2 rows) --- Resume execution and moving on to truncate segments that were marked as AWAITING_DROP, there should be only 1. -SELECT gp_inject_fault('appendonly_after_truncate_segment_file', 'suspend', dbid) FROM gp_segment_configuration WHERE content = 1 AND role = 'p'; +SELECT gp_inject_fault('appendonly_after_truncate_segment_file', 'reset', dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; gp_inject_fault ----------------- Success: -(1 row) -SELECT gp_inject_fault('vacuum_ao_after_index_delete', 'reset', dbid) FROM gp_segment_configuration WHERE content = 1 AND role = 'p'; - gp_inject_fault ------------------ Success: -(1 row) -SELECT gp_wait_until_triggered_fault('appendonly_after_truncate_segment_file', 1, dbid) FROM gp_segment_configuration WHERE content = 1 AND role = 'p'; - gp_wait_until_triggered_fault -------------------------------- - Success: -(1 row) --- We are in post_cleanup phase and should have truncated the old segfile. Both indexes should be vacuumed by now, and heap_blks_vacuumed should also increased -1U: select relid::regclass as relname, phase, heap_blks_total, heap_blks_scanned, heap_blks_vacuumed, index_vacuum_count, max_dead_tuples, num_dead_tuples from pg_stat_progress_vacuum; - relname | phase | heap_blks_total | heap_blks_scanned | heap_blks_vacuumed | index_vacuum_count | max_dead_tuples | num_dead_tuples -------------------------+------------------------------+-----------------+-------------------+--------------------+--------------------+-----------------+----------------- - vacuum_progress_ao_row | append-optimized pre-cleanup | 83 | 0 | 55 | 2 | 50000 | 0 -(1 row) - -SELECT gp_inject_fault('appendonly_after_truncate_segment_file', 'reset', dbid) FROM gp_segment_configuration WHERE content = 1 AND role = 'p'; + Success: +(3 rows) +SELECT gp_inject_fault('vacuum_ao_after_index_delete', 'reset', dbid) FROM gp_segment_configuration WHERE content = 0 AND role = 'p'; gp_inject_fault ----------------- Success: @@ -230,110 +263,245 @@ SELECT gp_inject_fault('appendonly_after_truncate_segment_file', 'reset', dbid) 1<: <... completed> VACUUM --- Vacuum has finished, nothing should show up in the progress view. -1U: select relid::regclass as relname, phase, heap_blks_total, heap_blks_scanned, heap_blks_vacuumed, index_vacuum_count, max_dead_tuples, num_dead_tuples from pg_stat_progress_vacuum; +-- Vacuum has finished, nothing should show up in the view. +select relid::regclass as relname, phase, heap_blks_total, heap_blks_scanned, heap_blks_vacuumed, index_vacuum_count, max_dead_tuples, num_dead_tuples from gp_stat_progress_vacuum where gp_segment_id = 1; + relname | phase | heap_blks_total | heap_blks_scanned | heap_blks_vacuumed | index_vacuum_count | max_dead_tuples | num_dead_tuples +---------+-------+-----------------+-------------------+--------------------+--------------------+-----------------+----------------- +(0 rows) +select relid::regclass as relname, phase, heap_blks_total, heap_blks_scanned, heap_blks_vacuumed, index_vacuum_count, max_dead_tuples, num_dead_tuples from gp_stat_progress_vacuum_summary; relname | phase | heap_blks_total | heap_blks_scanned | heap_blks_vacuumed | index_vacuum_count | max_dead_tuples | num_dead_tuples ---------+-------+-----------------+-------------------+--------------------+--------------------+-----------------+----------------- (0 rows) -- pg_class and collected stats view should be updated after the 2nd VACUUM -1U: SELECT wait_until_dead_tup_change_to('vacuum_progress_ao_row'::regclass::oid, 0); - wait_until_dead_tup_change_to -------------------------------- - OK +1U: SELECT wait_until_vacuum_count_change_to('vacuum_progress_ao_row'::regclass::oid, 2); + wait_until_vacuum_count_change_to +----------------------------------- + OK (1 row) SELECT relpages, reltuples, relallvisible FROM pg_class where relname = 'vacuum_progress_ao_row'; relpages | reltuples | relallvisible ----------+-----------+--------------- - 28 | 50000 | 0 + 30 | 50000 | 0 +(1 row) +SELECT n_live_tup, n_dead_tup, last_vacuum is not null as has_last_vacuum, vacuum_count FROM gp_stat_all_tables WHERE relname = 'vacuum_progress_ao_row' and gp_segment_id = 1; + n_live_tup | n_dead_tup | has_last_vacuum | vacuum_count +------------+------------+-----------------+-------------- + 16705 | 0 | t | 2 (1 row) -SELECT n_live_tup, n_dead_tup, last_vacuum is not null as has_last_vacuum, vacuum_count FROM pg_stat_all_tables WHERE relname = 'vacuum_progress_ao_row'; +SELECT n_live_tup, n_dead_tup, last_vacuum is not null as has_last_vacuum, vacuum_count FROM gp_stat_all_tables_summary WHERE relname = 'vacuum_progress_ao_row'; n_live_tup | n_dead_tup | has_last_vacuum | vacuum_count ------------+------------+-----------------+-------------- 50000 | 0 | t | 2 (1 row) --- open if system views gp_stat_progress_vacuum* are enabled ---1q: ----- Test vacuum worker process is changed at post-cleanup phase due to mirror down. ----- Current behavior is it will clear previous compact phase num_dead_tuples in post-cleanup ----- phase (at injecting point vacuum_ao_post_cleanup_end), which is different from above case ----- in which vacuum worker isn't changed. ---ALTER SYSTEM SET gp_fts_mark_mirror_down_grace_period to 10; ---ALTER SYSTEM SET gp_fts_probe_interval to 10; ---SELECT gp_segment_id, pg_reload_conf() FROM gp_id UNION SELECT gp_segment_id, pg_reload_conf() FROM gp_dist_random('gp_id'); --- ---DROP TABLE IF EXISTS vacuum_progress_ao_row; ---CREATE TABLE vacuum_progress_ao_row(i int, j int); ---CREATE INDEX on vacuum_progress_ao_row(i); ---CREATE INDEX on vacuum_progress_ao_row(j); ---1: BEGIN; ---2: BEGIN; ---1: INSERT INTO vacuum_progress_ao_row SELECT i, i FROM generate_series(1, 100000) i; ---2: INSERT INTO vacuum_progress_ao_row SELECT i, i FROM generate_series(1, 100000) i; ---2: COMMIT; ---2: BEGIN; ---2: INSERT INTO vacuum_progress_ao_row SELECT i, i FROM generate_series(1, 100000) i; ---2: ABORT; ---2q: ---1: ABORT; ---DELETE FROM vacuum_progress_ao_row where j % 2 = 0; --- ----- Suspend execution at the end of compact phase. ---2: SELECT gp_inject_fault('vacuum_ao_after_compact', 'suspend', dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; --- ---1: set debug_appendonly_print_compaction to on; ---1&: vacuum vacuum_progress_ao_row; --- ---2: SELECT gp_wait_until_triggered_fault('vacuum_ao_after_compact', 3, dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; --- ----- Non-zero progressing data num_dead_tuples is showed up. ---select gp_segment_id, relid::regclass as relname, phase, heap_blks_total, heap_blks_scanned, heap_blks_vacuumed, index_vacuum_count, max_dead_tuples, num_dead_tuples from gp_stat_progress_vacuum where gp_segment_id > -1; ---select relid::regclass as relname, phase, heap_blks_total, heap_blks_scanned, heap_blks_vacuumed, index_vacuum_count, max_dead_tuples, num_dead_tuples from gp_stat_progress_vacuum_summary; --- ----- Resume execution of compact phase and block at syncrep. ---2: SELECT gp_inject_fault_infinite('wal_sender_loop', 'suspend', dbid) FROM gp_segment_configuration WHERE role = 'p' and content = 1; ---2: SELECT gp_inject_fault('vacuum_ao_after_compact', 'reset', dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; ----- stop the mirror should turn off syncrep ---2: SELECT pg_ctl(datadir, 'stop', 'immediate') FROM gp_segment_configuration WHERE content=1 AND role = 'm'; --- ----- Resume walsender to detect mirror down and suspend at the beginning ----- of post-cleanup taken over by a new vacuum worker. ---2: SELECT gp_inject_fault('vacuum_worker_changed', 'suspend', dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; ----- resume walsender and let it exit so that mirror stop can be detected ---2: SELECT gp_inject_fault_infinite('wal_sender_loop', 'reset', dbid) FROM gp_segment_configuration WHERE role = 'p' and content = 1; ----- Ensure we enter into the target logic which stops cumulative data but ----- initializes a new vacrelstats at the beginning of post-cleanup phase. ----- Also all segments should reach to the same "vacuum_worker_changed" point ----- due to FTS version being changed. ---2: SELECT gp_wait_until_triggered_fault('vacuum_worker_changed', 1, dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; ----- now seg1's mirror is marked as down ---2: SELECT content, role, preferred_role, mode, status FROM gp_segment_configuration WHERE content > -1; --- ----- Resume execution and entering post_cleaup phase, suspend at the end of it. ---2: SELECT gp_inject_fault('vacuum_ao_post_cleanup_end', 'suspend', dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; ---2: SELECT gp_inject_fault('vacuum_worker_changed', 'reset', dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; ---2: SELECT gp_wait_until_triggered_fault('vacuum_ao_post_cleanup_end', 1, dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; --- ----- The previous collected num_dead_tuples in compact phase is zero. ---select gp_segment_id, relid::regclass as relname, phase, heap_blks_total, heap_blks_scanned, heap_blks_vacuumed, index_vacuum_count, max_dead_tuples, num_dead_tuples from gp_stat_progress_vacuum where gp_segment_id > -1; ---select relid::regclass as relname, phase, heap_blks_total, heap_blks_scanned, heap_blks_vacuumed, index_vacuum_count, max_dead_tuples, num_dead_tuples from gp_stat_progress_vacuum_summary; --- ---2: SELECT gp_inject_fault('vacuum_ao_post_cleanup_end', 'reset', dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; --- ---1<: --- ----- restore environment ---1: reset debug_appendonly_print_compaction; --- ---2: SELECT pg_ctl_start(datadir, port) FROM gp_segment_configuration WHERE role = 'm' AND content = 1; ---2: SELECT wait_until_all_segments_synchronized(); --- ----- Cleanup ---SELECT gp_inject_fault_infinite('all', 'reset', dbid) FROM gp_segment_configuration; ---reset Debug_appendonly_print_compaction; ---reset default_table_access_method; ---ALTER SYSTEM RESET gp_fts_mark_mirror_down_grace_period; ---ALTER SYSTEM RESET gp_fts_probe_interval; ---SELECT gp_segment_id, pg_reload_conf() FROM gp_id UNION SELECT gp_segment_id, pg_reload_conf() FROM gp_dist_random('gp_id'); --- +1q: ... +-- Test vacuum worker process is changed at post-cleanup phase due to mirror down. +-- Current behavior is it will clear previous compact phase num_dead_tuples in post-cleanup +-- phase (at injecting point vacuum_ao_post_cleanup_end), which is different from above case +-- in which vacuum worker isn't changed. +DROP TABLE IF EXISTS vacuum_progress_ao_row; +DROP +CREATE TABLE vacuum_progress_ao_row(i int, j int); +CREATE +CREATE INDEX on vacuum_progress_ao_row(i); +CREATE +CREATE INDEX on vacuum_progress_ao_row(j); +CREATE +1: BEGIN; +BEGIN +2: BEGIN; +BEGIN +1: INSERT INTO vacuum_progress_ao_row SELECT i, i FROM generate_series(1, 100000) i; +INSERT 100000 +2: INSERT INTO vacuum_progress_ao_row SELECT i, i FROM generate_series(1, 100000) i; +INSERT 100000 +2: COMMIT; +COMMIT +2: BEGIN; +BEGIN +2: INSERT INTO vacuum_progress_ao_row SELECT i, i FROM generate_series(1, 100000) i; +INSERT 100000 +2: ABORT; +ABORT +2q: ... +1: ABORT; +ABORT +DELETE FROM vacuum_progress_ao_row where j % 2 = 0; +DELETE 50000 + +-- Suspend execution at the end of compact phase. +2: SELECT gp_inject_fault('vacuum_ao_after_compact', 'suspend', dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; + gp_inject_fault +----------------- + Success: + Success: + Success: +(3 rows) + +1: set debug_appendonly_print_compaction to on; +SET +1&: vacuum vacuum_progress_ao_row; + +2: SELECT gp_wait_until_triggered_fault('vacuum_ao_after_compact', 1, dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; + gp_wait_until_triggered_fault +------------------------------- + Success: + Success: + Success: +(3 rows) + +-- Non-zero progressing data num_dead_tuples is showed up. +select gp_segment_id, relid::regclass as relname, phase, heap_blks_total, heap_blks_scanned, heap_blks_vacuumed, index_vacuum_count, max_dead_tuples, num_dead_tuples from gp_stat_progress_vacuum where gp_segment_id > -1; + gp_segment_id | relname | phase | heap_blks_total | heap_blks_scanned | heap_blks_vacuumed | index_vacuum_count | max_dead_tuples | num_dead_tuples +---------------+------------------------+--------------------------+-----------------+-------------------+--------------------+--------------------+-----------------+----------------- + 1 | vacuum_progress_ao_row | append-optimized compact | 55 | 19 | 37 | 0 | 33327 | 16622 + 2 | vacuum_progress_ao_row | append-optimized compact | 55 | 19 | 37 | 0 | 33211 | 16653 + 0 | vacuum_progress_ao_row | append-optimized compact | 56 | 19 | 37 | 0 | 33462 | 16725 +(3 rows) +select relid::regclass as relname, phase, heap_blks_total, heap_blks_scanned, heap_blks_vacuumed, index_vacuum_count, max_dead_tuples, num_dead_tuples from gp_stat_progress_vacuum_summary; + relname | phase | heap_blks_total | heap_blks_scanned | heap_blks_vacuumed | index_vacuum_count | max_dead_tuples | num_dead_tuples +------------------------+--------------------------+-----------------+-------------------+--------------------+--------------------+-----------------+----------------- + vacuum_progress_ao_row | append-optimized compact | 166 | 57 | 111 | 0 | 100000 | 50000 +(1 row) + +-- Resume execution of compact phase and block at syncrep. +2: SELECT gp_inject_fault_infinite('wal_sender_loop', 'suspend', dbid) FROM gp_segment_configuration WHERE role = 'p' and content = 1; + gp_inject_fault_infinite +-------------------------- + Success: +(1 row) +2: SELECT gp_inject_fault('vacuum_ao_after_compact', 'reset', dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; + gp_inject_fault +----------------- + Success: + Success: + Success: +(3 rows) +-- stop the mirror should turn off syncrep +2: SELECT pg_ctl(datadir, 'stop', 'immediate') FROM gp_segment_configuration WHERE content=1 AND role = 'm'; + pg_ctl +-------- + OK +(1 row) + +-- Resume walsender to detect mirror down and suspend at the beginning +-- of post-cleanup taken over by a new vacuum worker. +2: SELECT gp_inject_fault('vacuum_worker_changed', 'suspend', dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; + gp_inject_fault +----------------- + Success: + Success: + Success: +(3 rows) +-- resume walsender and let it exit so that mirror stop can be detected +2: SELECT gp_inject_fault_infinite('wal_sender_loop', 'reset', dbid) FROM gp_segment_configuration WHERE role = 'p' and content = 1; + gp_inject_fault_infinite +-------------------------- + Success: +(1 row) +-- Ensure we enter into the target logic which stops cumulative data but +-- initializes a new vacrelstats at the beginning of post-cleanup phase. +-- Also all segments should reach to the same "vacuum_worker_changed" point +-- due to FTS version being changed. +2: SELECT gp_wait_until_triggered_fault('vacuum_worker_changed', 1, dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; + gp_wait_until_triggered_fault +------------------------------- + Success: + Success: + Success: +(3 rows) +-- now seg1's mirror is marked as down +2: SELECT content, role, preferred_role, mode, status FROM gp_segment_configuration WHERE content > -1; + content | role | preferred_role | mode | status +---------+------+----------------+------+-------- + 2 | p | p | s | u + 2 | m | m | s | u + 0 | p | p | s | u + 0 | m | m | s | u + 1 | p | p | n | u + 1 | m | m | n | d +(6 rows) + +-- Resume execution and entering post_cleaup phase, suspend at the end of it. +2: SELECT gp_inject_fault('vacuum_ao_post_cleanup_end', 'suspend', dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; + gp_inject_fault +----------------- + Success: + Success: + Success: +(3 rows) +2: SELECT gp_inject_fault('vacuum_worker_changed', 'reset', dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; + gp_inject_fault +----------------- + Success: + Success: + Success: +(3 rows) +2: SELECT gp_wait_until_triggered_fault('vacuum_ao_post_cleanup_end', 1, dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; + gp_wait_until_triggered_fault +------------------------------- + Success: + Success: + Success: +(3 rows) + +-- The previous collected num_dead_tuples in compact phase is zero. +select gp_segment_id, relid::regclass as relname, phase, heap_blks_total, heap_blks_scanned, heap_blks_vacuumed, index_vacuum_count, max_dead_tuples, num_dead_tuples from gp_stat_progress_vacuum where gp_segment_id > -1; + gp_segment_id | relname | phase | heap_blks_total | heap_blks_scanned | heap_blks_vacuumed | index_vacuum_count | max_dead_tuples | num_dead_tuples +---------------+------------------------+-------------------------------+-----------------+-------------------+--------------------+--------------------+-----------------+----------------- + 0 | vacuum_progress_ao_row | append-optimized post-cleanup | 0 | 0 | 0 | 0 | 0 | 0 + 2 | vacuum_progress_ao_row | append-optimized post-cleanup | 0 | 0 | 0 | 0 | 0 | 0 + 1 | vacuum_progress_ao_row | append-optimized post-cleanup | 0 | 0 | 0 | 0 | 0 | 0 +(3 rows) +select relid::regclass as relname, phase, heap_blks_total, heap_blks_scanned, heap_blks_vacuumed, index_vacuum_count, max_dead_tuples, num_dead_tuples from gp_stat_progress_vacuum_summary; + relname | phase | heap_blks_total | heap_blks_scanned | heap_blks_vacuumed | index_vacuum_count | max_dead_tuples | num_dead_tuples +------------------------+-------------------------------+-----------------+-------------------+--------------------+--------------------+-----------------+----------------- + vacuum_progress_ao_row | append-optimized post-cleanup | 0 | 0 | 0 | 0 | 0 | 0 +(1 row) + +2: SELECT gp_inject_fault('vacuum_ao_post_cleanup_end', 'reset', dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; + gp_inject_fault +----------------- + Success: + Success: + Success: +(3 rows) + +1<: <... completed> +VACUUM + +-- restore environment +1: reset debug_appendonly_print_compaction; +RESET + +2: SELECT pg_ctl_start(datadir, port) FROM gp_segment_configuration WHERE role = 'm' AND content = 1; + pg_ctl_start +-------------------------------------------------- + waiting for server to start done +server started + +(1 row) +2: SELECT wait_until_all_segments_synchronized(); + wait_until_all_segments_synchronized +-------------------------------------- + OK +(1 row) + +-- Cleanup +SELECT gp_inject_fault_infinite('all', 'reset', dbid) FROM gp_segment_configuration; + gp_inject_fault_infinite +-------------------------- + Success: + Success: + Success: + Success: + Success: + Success: + Success: + Success: +(8 rows) +reset Debug_appendonly_print_compaction; +RESET +reset default_table_access_method; +RESET diff --git a/src/test/isolation2/input/autovacuum-analyze.source b/src/test/isolation2/input/autovacuum-analyze.source index 32e79cdd491..19187b107c2 100644 --- a/src/test/isolation2/input/autovacuum-analyze.source +++ b/src/test/isolation2/input/autovacuum-analyze.source @@ -178,7 +178,7 @@ SELECT count(*) FROM pg_statistic where starelid = 'autostatstbl'::regclass; select relpages, reltuples from pg_class where oid = 'autostatstbl'::regclass; -- expect analyze_count = 1, autoanalyze_count = 0, and n_mod_since_analyze = 1000 since ANALYZE executed -- in same transaction for the insert statement. -select analyze_count, autoanalyze_count, n_mod_since_analyze from pg_stat_all_tables_internal where relname = 'autostatstbl'; +select analyze_count, autoanalyze_count, n_mod_since_analyze from pg_stat_all_tables where relname = 'autostatstbl'; -- Wait until autovacuum is triggered SELECT gp_wait_until_triggered_fault('auto_vac_worker_after_report_activity', 1, 1); @@ -192,7 +192,7 @@ SELECT gp_inject_fault('analyze_finished_one_relation', 'reset', 1); -- we can see the auto-ANALYZE finished select relpages, reltuples from pg_class where oid = 'autostatstbl'::regclass; -- expect analyze_count = 1, autoanalyze_count = 1, and n_mod_since_analyze = 0 -select analyze_count, autoanalyze_count, n_mod_since_analyze from pg_stat_all_tables_internal where relname = 'autostatstbl'; +select analyze_count, autoanalyze_count, n_mod_since_analyze from pg_stat_all_tables where relname = 'autostatstbl'; -- Case 2 -- -- with auto_stats 'on_change' mode, the auto-ANALYZE still trigger @@ -211,7 +211,7 @@ SELECT gp_inject_fault('auto_vac_worker_after_report_activity', 'suspend', '', ' select relpages, reltuples from pg_class where oid = 'autostatstbl'::regclass; -- expect analyze_count = 2, autoanalyze_count = 1, and n_mod_since_analyze = 1000 since ANALYZE executed -- in same transaction for the insert statement. -select analyze_count, autoanalyze_count, n_mod_since_analyze from pg_stat_all_tables_internal where relname = 'autostatstbl'; +select analyze_count, autoanalyze_count, n_mod_since_analyze from pg_stat_all_tables where relname = 'autostatstbl'; -- Wait until autovacuum is triggered SELECT gp_wait_until_triggered_fault('auto_vac_worker_after_report_activity', 1, 1); @@ -225,7 +225,7 @@ SELECT gp_inject_fault('analyze_finished_one_relation', 'reset', 1); -- we can see the auto-ANALYZE finished, check statistic and analyze count select relpages, reltuples from pg_class where oid = 'autostatstbl'::regclass; -- expect analyze_count = 2, autoanalyze_count = 2, and n_mod_since_analyze = 0 -select analyze_count, autoanalyze_count, n_mod_since_analyze from pg_stat_all_tables_internal where relname = 'autostatstbl'; +select analyze_count, autoanalyze_count, n_mod_since_analyze from pg_stat_all_tables where relname = 'autostatstbl'; -- Case 3 -- @@ -244,7 +244,7 @@ SELECT gp_inject_fault('auto_vac_worker_after_report_activity', 'suspend', '', ' select relpages, reltuples from pg_class where oid = 'autostatstbl'::regclass; -- expect analyze_count = 2, autoanalyze_count = 2, and n_mod_since_analyze = 1000 since ANALYZE executed -- in same transaction for the insert statement. -select analyze_count, autoanalyze_count, n_mod_since_analyze from pg_stat_all_tables_internal where relname = 'autostatstbl'; +select analyze_count, autoanalyze_count, n_mod_since_analyze from pg_stat_all_tables where relname = 'autostatstbl'; -- Wait until autovacuum is triggered SELECT gp_wait_until_triggered_fault('auto_vac_worker_after_report_activity', 1, 1); @@ -258,7 +258,7 @@ SELECT gp_inject_fault('analyze_finished_one_relation', 'reset', 1); -- we can see the auto-ANALYZE finished, check statistic and analyze count select relpages, reltuples from pg_class where oid = 'autostatstbl'::regclass; -- expect analyze_count = 2, autoanalyze_count = 3, and n_mod_since_analyze = 0 since ANALYZE executed -select analyze_count, autoanalyze_count, n_mod_since_analyze from pg_stat_all_tables_internal where relname = 'autostatstbl'; +select analyze_count, autoanalyze_count, n_mod_since_analyze from pg_stat_all_tables where relname = 'autostatstbl'; -- Reset GUCs. ALTER SYSTEM RESET autovacuum_naptime; diff --git a/src/test/isolation2/isolation2_schedule b/src/test/isolation2/isolation2_schedule index 18fd4a2c0c4..0b2a16544dc 100644 --- a/src/test/isolation2/isolation2_schedule +++ b/src/test/isolation2/isolation2_schedule @@ -234,6 +234,7 @@ test: idle_gang_cleaner # test idle_in_transaction_session_timeout test: ao_index_build_progress +test: analyze_progress # Tests for FTS test: fts_errors diff --git a/src/test/isolation2/output/autovacuum-analyze.source b/src/test/isolation2/output/autovacuum-analyze.source index e071f9e7007..b8727a10a51 100644 --- a/src/test/isolation2/output/autovacuum-analyze.source +++ b/src/test/isolation2/output/autovacuum-analyze.source @@ -422,7 +422,7 @@ select relpages, reltuples from pg_class where oid = 'autostatstbl'::regclass; (1 row) -- expect analyze_count = 1, autoanalyze_count = 0, and n_mod_since_analyze = 1000 since ANALYZE executed -- in same transaction for the insert statement. -select analyze_count, autoanalyze_count, n_mod_since_analyze from pg_stat_all_tables_internal where relname = 'autostatstbl'; +select analyze_count, autoanalyze_count, n_mod_since_analyze from pg_stat_all_tables where relname = 'autostatstbl'; analyze_count | autoanalyze_count | n_mod_since_analyze ---------------+-------------------+--------------------- 1 | 0 | 1000 @@ -465,7 +465,7 @@ select relpages, reltuples from pg_class where oid = 'autostatstbl'::regclass; 3 | 1000 (1 row) -- expect analyze_count = 1, autoanalyze_count = 1, and n_mod_since_analyze = 0 -select analyze_count, autoanalyze_count, n_mod_since_analyze from pg_stat_all_tables_internal where relname = 'autostatstbl'; +select analyze_count, autoanalyze_count, n_mod_since_analyze from pg_stat_all_tables where relname = 'autostatstbl'; analyze_count | autoanalyze_count | n_mod_since_analyze ---------------+-------------------+--------------------- 1 | 1 | 0 @@ -502,7 +502,7 @@ select relpages, reltuples from pg_class where oid = 'autostatstbl'::regclass; (1 row) -- expect analyze_count = 2, autoanalyze_count = 1, and n_mod_since_analyze = 1000 since ANALYZE executed -- in same transaction for the insert statement. -select analyze_count, autoanalyze_count, n_mod_since_analyze from pg_stat_all_tables_internal where relname = 'autostatstbl'; +select analyze_count, autoanalyze_count, n_mod_since_analyze from pg_stat_all_tables where relname = 'autostatstbl'; analyze_count | autoanalyze_count | n_mod_since_analyze ---------------+-------------------+--------------------- 2 | 1 | 1000 @@ -545,7 +545,7 @@ select relpages, reltuples from pg_class where oid = 'autostatstbl'::regclass; 3 | 2000 (1 row) -- expect analyze_count = 2, autoanalyze_count = 2, and n_mod_since_analyze = 0 -select analyze_count, autoanalyze_count, n_mod_since_analyze from pg_stat_all_tables_internal where relname = 'autostatstbl'; +select analyze_count, autoanalyze_count, n_mod_since_analyze from pg_stat_all_tables where relname = 'autostatstbl'; analyze_count | autoanalyze_count | n_mod_since_analyze ---------------+-------------------+--------------------- 2 | 2 | 0 @@ -581,7 +581,7 @@ select relpages, reltuples from pg_class where oid = 'autostatstbl'::regclass; (1 row) -- expect analyze_count = 2, autoanalyze_count = 2, and n_mod_since_analyze = 1000 since ANALYZE executed -- in same transaction for the insert statement. -select analyze_count, autoanalyze_count, n_mod_since_analyze from pg_stat_all_tables_internal where relname = 'autostatstbl'; +select analyze_count, autoanalyze_count, n_mod_since_analyze from pg_stat_all_tables where relname = 'autostatstbl'; analyze_count | autoanalyze_count | n_mod_since_analyze ---------------+-------------------+--------------------- 2 | 2 | 1000 @@ -624,7 +624,7 @@ select relpages, reltuples from pg_class where oid = 'autostatstbl'::regclass; 6 | 3000 (1 row) -- expect analyze_count = 2, autoanalyze_count = 3, and n_mod_since_analyze = 0 since ANALYZE executed -select analyze_count, autoanalyze_count, n_mod_since_analyze from pg_stat_all_tables_internal where relname = 'autostatstbl'; +select analyze_count, autoanalyze_count, n_mod_since_analyze from pg_stat_all_tables where relname = 'autostatstbl'; analyze_count | autoanalyze_count | n_mod_since_analyze ---------------+-------------------+--------------------- 2 | 3 | 0 diff --git a/src/test/isolation2/output/parallel_retrieve_cursor/explain.source b/src/test/isolation2/output/parallel_retrieve_cursor/explain.source index e26fe7bd9fa..15baecb724f 100644 --- a/src/test/isolation2/output/parallel_retrieve_cursor/explain.source +++ b/src/test/isolation2/output/parallel_retrieve_cursor/explain.source @@ -129,14 +129,17 @@ EXPLAIN (VERBOSE, COSTS false) DECLARE c1 PARALLEL RETRIEVE CURSOR FOR SELECT * Optimizer: Postgres query optimizer (5 rows) EXPLAIN (VERBOSE, COSTS false) DECLARE c1 PARALLEL RETRIEVE CURSOR FOR SELECT * FROM pg_class ORDER BY relname; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - Index Scan using pg_class_relname_nsp_index on pg_catalog.pg_class - Output: oid, relname, relnamespace, reltype, reloftype, relowner, relam, relfilenode, reltablespace, relpages, reltuples, relallvisible, reltoastrelid, relhasindex, relisshared, relpersistence, relkind, relnatts, relchecks, relhasrules, relhastriggers, relhassubclass, relrowsecurity, relforcerowsecurity, relispopulated, relreplident, relispartition, relisivm, relisdynamic, relmvrefcount, relrewrite, relfrozenxid, relminmxid, relacl, reloptions, relpartbound - Settings: enable_incremental_sort = 'on' - Endpoint: "on coordinator" - Optimizer: Postgres query optimizer -(5 rows) + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ + Sort + Output: oid, relname, relnamespace, reltype, reloftype, relowner, relam, relfilenode, reltablespace, relpages, reltuples, relallvisible, reltoastrelid, relhasindex, relisshared, relpersistence, relkind, relnatts, relchecks, relhasrules, relhastriggers, relhassubclass, relrowsecurity, relforcerowsecurity, relispopulated, relreplident, relispartition, relisivm, relisdynamic, relmvrefcount, relrewrite, relfrozenxid, relminmxid, relacl, reloptions, relpartbound + Sort Key: pg_class.relname + -> Seq Scan on pg_catalog.pg_class + Output: oid, relname, relnamespace, reltype, reloftype, relowner, relam, relfilenode, reltablespace, relpages, reltuples, relallvisible, reltoastrelid, relhasindex, relisshared, relpersistence, relkind, relnatts, relchecks, relhasrules, relhastriggers, relhassubclass, relrowsecurity, relforcerowsecurity, relispopulated, relreplident, relispartition, relisivm, relisdynamic, relmvrefcount, relrewrite, relfrozenxid, relminmxid, relacl, reloptions, relpartbound + Settings: enable_incremental_sort = 'on' + Endpoint: "on coordinator" + Optimizer: Postgres query optimizer +(8 rows) EXPLAIN (VERBOSE, COSTS false) DECLARE c1 PARALLEL RETRIEVE CURSOR FOR SELECT * FROM pg_class WHERE gp_segment_id=1; QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ diff --git a/src/test/isolation2/sql/analyze_progress.sql b/src/test/isolation2/sql/analyze_progress.sql new file mode 100644 index 00000000000..311ab161eb2 --- /dev/null +++ b/src/test/isolation2/sql/analyze_progress.sql @@ -0,0 +1,42 @@ +-- Test gp_stat_progress_analyze_summary +-- setup hash distributed table +CREATE TABLE t_analyze_part (a INT, b INT) DISTRIBUTED BY (a); +INSERT INTO t_analyze_part SELECT i, i FROM generate_series(1, 100000) i; + +-- Suspend analyze after scanning 20 blocks on each segment +SELECT gp_inject_fault('analyze_block', 'suspend', '', '', '', 20, 20, 0, dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; + +-- session 1: analyze the table +1&: ANALYZE t_analyze_part; +SELECT gp_wait_until_triggered_fault('analyze_block', 1, dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; + +-- session 2: query pg_stat_progress_analyze while the analyze is running, the view should indicate 60 blocks have been scanned as aggregated progress of 3 segments +2: SELECT pid IS NOT NULL as has_pid, datname, relid::regclass, phase, sample_blks_total, sample_blks_scanned FROM gp_stat_progress_analyze_summary; + +-- Reset fault injector +SELECT gp_inject_fault('analyze_block', 'reset', dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; +1<: + +-- teardown +DROP TABLE t_analyze_part; + +-- setup replicated table +CREATE TABLE t_analyze_repl (a INT, b INT) DISTRIBUTED REPLICATED; +INSERT INTO t_analyze_repl SELECT i, i FROM generate_series(1, 100000) i; + +-- Suspend analyze after scanning 20 blocks on each segment +SELECT gp_inject_fault('analyze_block', 'suspend', '', '', '', 20, 20, 0, dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; + +-- session 1: analyze the table +1&: ANALYZE t_analyze_repl; +SELECT gp_wait_until_triggered_fault('analyze_block', 1, dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; + +-- session 2: query pg_stat_progress_analyze while the analyze is running, the view should indicate 20 blocks have been scanned as average progress of 3 segments +2: SELECT pid IS NOT NULL as has_pid, datname, relid::regclass, phase, sample_blks_total, sample_blks_scanned FROM gp_stat_progress_analyze_summary; + +-- Reset fault injector +SELECT gp_inject_fault('analyze_block', 'reset', dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; +1<: + +-- teardown +DROP TABLE t_analyze_repl; diff --git a/src/test/isolation2/sql/ao_index_build_progress.sql b/src/test/isolation2/sql/ao_index_build_progress.sql index 19aade99e29..c5e34d1eab7 100644 --- a/src/test/isolation2/sql/ao_index_build_progress.sql +++ b/src/test/isolation2/sql/ao_index_build_progress.sql @@ -7,30 +7,34 @@ CREATE TABLE ao_index_build_progress(i int, j bigint) USING ao_row -- Insert all tuples to seg1. INSERT INTO ao_index_build_progress SELECT 0, i FROM generate_series(1, 100000) i; +INSERT INTO ao_index_build_progress SELECT 2, i FROM generate_series(1, 100000) i; +INSERT INTO ao_index_build_progress SELECT 5, i FROM generate_series(1, 100000) i; -- Suspend execution when some blocks have been read. SELECT gp_inject_fault('AppendOnlyStorageRead_ReadNextBlock_success', 'suspend', '', '', '', 10, 10, 0, dbid) - FROM gp_segment_configuration WHERE content = 1 AND role = 'p'; + FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; 1&: CREATE INDEX ON ao_index_build_progress(i); -- Wait until some AO varblocks have been read. SELECT gp_wait_until_triggered_fault('AppendOnlyStorageRead_ReadNextBlock_success', 10, dbid) - FROM gp_segment_configuration WHERE content = 1 AND role = 'p'; + FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; -- By now, we should have reported some blocks (of size 'block_size') as "done", -- as well as a total number of blocks that matches the relation's on-disk size. -1U: SELECT command, phase, +SELECT command, phase, (pg_relation_size('ao_index_build_progress') + (current_setting('block_size')::int - 1)) / current_setting('block_size')::int AS blocks_total_actual, blocks_total AS blocks_total_reported, blocks_done AS blocks_done_reported - FROM pg_stat_progress_create_index - WHERE relid = 'ao_index_build_progress'::regclass; + FROM gp_stat_progress_create_index + WHERE gp_segment_id = 1 AND relid = 'ao_index_build_progress'::regclass; +-- The same should be true for the summary view, and the total number of blocks should be tripled. +SELECT command, phase, blocks_total, blocks_done FROM gp_stat_progress_create_index_summary WHERE relid = 'ao_index_build_progress'::regclass; SELECT gp_inject_fault('AppendOnlyStorageRead_ReadNextBlock_success', 'reset', dbid) - FROM gp_segment_configuration WHERE content = 1 AND role = 'p'; + FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; 1<: @@ -40,31 +44,35 @@ CREATE TABLE aoco_index_build_progress(i int, j int ENCODING (compresstype=zstd, -- Insert all tuples to seg1. INSERT INTO aoco_index_build_progress SELECT 0, i FROM generate_series(1, 100000) i; +INSERT INTO aoco_index_build_progress SELECT 2, i FROM generate_series(1, 100000) i; +INSERT INTO aoco_index_build_progress SELECT 5, i FROM generate_series(1, 100000) i; -- Suspend execution when some blocks have been read. SELECT gp_inject_fault('AppendOnlyStorageRead_ReadNextBlock_success', 'suspend', '', '', '', 5, 5, 0, dbid) - FROM gp_segment_configuration WHERE content = 1 AND role = 'p'; + FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; 1&: CREATE INDEX ON aoco_index_build_progress(i); -- Wait until some AOCO varblocks have been read. SELECT gp_wait_until_triggered_fault('AppendOnlyStorageRead_ReadNextBlock_success', 5, dbid) - FROM gp_segment_configuration WHERE content = 1 AND role = 'p'; + FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; -- By now, we should have reported some blocks (of size 'block_size') as "done", -- as well as a total number of blocks that matches the relation's on-disk size. -- Note: all blocks for the relation have to be scanned as we are building an -- index for the first time and a block directory has to be created. -1U: SELECT command, phase, +SELECT command, phase, (pg_relation_size('aoco_index_build_progress') + (current_setting('block_size')::int - 1)) / current_setting('block_size')::int AS blocks_total_actual, blocks_total AS blocks_total_reported, blocks_done AS blocks_done_reported - FROM pg_stat_progress_create_index - WHERE relid = 'aoco_index_build_progress'::regclass; + FROM gp_stat_progress_create_index + WHERE gp_segment_id = 1 AND relid = 'aoco_index_build_progress'::regclass; +-- The same should be true for the summary view, and the total number of blocks should be tripled. +SELECT command, phase, blocks_total, blocks_done FROM gp_stat_progress_create_index_summary WHERE relid = 'aoco_index_build_progress'::regclass; SELECT gp_inject_fault('AppendOnlyStorageRead_ReadNextBlock_success', 'reset', dbid) - FROM gp_segment_configuration WHERE content = 1 AND role = 'p'; + FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; 1<: @@ -72,13 +80,13 @@ SELECT gp_inject_fault('AppendOnlyStorageRead_ReadNextBlock_success', 'reset', d -- Suspend execution when some blocks have been read. SELECT gp_inject_fault('AppendOnlyStorageRead_ReadNextBlock_success', 'suspend', '', '', '', 5, 5, 0, dbid) - FROM gp_segment_configuration WHERE content = 1 AND role = 'p'; + FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; 1&: CREATE INDEX ON aoco_index_build_progress(j); -- Wait until some AOCO varblocks have been read. SELECT gp_wait_until_triggered_fault('AppendOnlyStorageRead_ReadNextBlock_success', 5, dbid) - FROM gp_segment_configuration WHERE content = 1 AND role = 'p'; + FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; -- By now, we should have reported some blocks (of size 'block_size') as "done", -- as well as a total number of blocks that matches the size of col j's segfile. @@ -90,10 +98,12 @@ SELECT gp_wait_until_triggered_fault('AppendOnlyStorageRead_ReadNextBlock_succes AS col_j_blocks, blocks_total AS blocks_total_reported, blocks_done AS blocks_done_reported - FROM pg_stat_progress_create_index - WHERE relid = 'aoco_index_build_progress'::regclass; + FROM gp_stat_progress_create_index + WHERE gp_segment_id = 1 AND relid = 'aoco_index_build_progress'::regclass; +-- The same should be true for the summary view, and the total number of blocks should be tripled. +SELECT command, phase, blocks_total, blocks_done FROM gp_stat_progress_create_index_summary WHERE relid = 'aoco_index_build_progress'::regclass; SELECT gp_inject_fault('AppendOnlyStorageRead_ReadNextBlock_success', 'reset', dbid) - FROM gp_segment_configuration WHERE content = 1 AND role = 'p'; + FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; 1<: diff --git a/src/test/isolation2/sql/vacuum_progress_column.sql b/src/test/isolation2/sql/vacuum_progress_column.sql index 648d43303be..cff0d8394ba 100644 --- a/src/test/isolation2/sql/vacuum_progress_column.sql +++ b/src/test/isolation2/sql/vacuum_progress_column.sql @@ -30,10 +30,6 @@ CREATE INDEX on vacuum_progress_ao_column(j); -- Also delete half of the tuples evenly before the EOF of segno 2. DELETE FROM vacuum_progress_ao_column where j % 2 = 0; --- Lookup pg_class and collected stats view before VACUUM -SELECT relpages, reltuples, relallvisible FROM pg_class where relname = 'vacuum_progress_ao_column'; -SELECT n_live_tup, n_dead_tup, last_vacuum, vacuum_count FROM pg_stat_all_tables WHERE relname = 'vacuum_progress_ao_column'; - -- Perform VACUUM and observe the progress -- Suspend execution at pre-cleanup phase after truncating both segfiles to their logical EOF. @@ -71,7 +67,7 @@ SELECT gp_inject_fault('vacuum_ao_post_cleanup_end', 'reset', dbid) FROM gp_segm -- pg_class and collected stats view should be updated after the 1st VACUUM 1U: SELECT wait_until_dead_tup_change_to('vacuum_progress_ao_column'::regclass::oid, 0); SELECT relpages, reltuples, relallvisible FROM pg_class where relname = 'vacuum_progress_ao_column'; -SELECT n_live_tup, n_dead_tup, last_vacuum is not null as has_last_vacuum, vacuum_count FROM pg_stat_all_tables WHERE relname = 'vacuum_progress_ao_column'; +SELECT n_live_tup, n_dead_tup, last_vacuum is not null as has_last_vacuum, vacuum_count FROM gp_stat_all_tables WHERE relname = 'vacuum_progress_ao_column' and gp_segment_id = 1; -- Perform VACUUM again to recycle the remaining awaiting drop segment marked by the previous run. @@ -99,17 +95,13 @@ SELECT gp_inject_fault('appendonly_after_truncate_segment_file', 'reset', dbid) -- pg_class and collected stats view should be updated after the 2nd VACUUM 1U: SELECT wait_until_dead_tup_change_to('vacuum_progress_ao_column'::regclass::oid, 0); SELECT relpages, reltuples, relallvisible FROM pg_class where relname = 'vacuum_progress_ao_column'; -SELECT n_live_tup, n_dead_tup, last_vacuum is not null as has_last_vacuum, vacuum_count FROM pg_stat_all_tables WHERE relname = 'vacuum_progress_ao_column'; +SELECT n_live_tup, n_dead_tup, last_vacuum is not null as has_last_vacuum, vacuum_count FROM gp_stat_all_tables WHERE relname = 'vacuum_progress_ao_column' and gp_segment_id = 1; 1q: -- Test vacuum worker process is changed at post-cleanup phase due to mirror down. -- Current behavior is it will clear previous compact phase num_dead_tuples in post-cleanup -- phase (at injecting point vacuum_ao_post_cleanup_end), which is different from above case -- in which vacuum worker isn't changed. -ALTER SYSTEM SET gp_fts_mark_mirror_down_grace_period to 10; -ALTER SYSTEM SET gp_fts_probe_interval to 10; -SELECT gp_segment_id, pg_reload_conf() FROM gp_id UNION SELECT gp_segment_id, pg_reload_conf() FROM gp_dist_random('gp_id'); - DROP TABLE IF EXISTS vacuum_progress_ao_column; CREATE TABLE vacuum_progress_ao_column(i int, j int); CREATE INDEX on vacuum_progress_ao_column(i); @@ -132,7 +124,7 @@ DELETE FROM vacuum_progress_ao_column where j % 2 = 0; 1: set debug_appendonly_print_compaction to on; 1&: vacuum vacuum_progress_ao_column; -2: SELECT gp_wait_until_triggered_fault('vacuum_ao_after_compact', 3, dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; +2: SELECT gp_wait_until_triggered_fault('vacuum_ao_after_compact', 1, dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; -- Non-zero progressing data num_dead_tuples is showed up. select gp_segment_id, relid::regclass as relname, phase, heap_blks_total, heap_blks_scanned, heap_blks_vacuumed, index_vacuum_count, max_dead_tuples, num_dead_tuples from gp_stat_progress_vacuum where gp_segment_id > -1; @@ -153,14 +145,14 @@ select relid::regclass as relname, phase, heap_blks_total, heap_blks_scanned, he -- initializes a new vacrelstats at the beginning of post-cleanup phase. -- Also all segments should reach to the same "vacuum_worker_changed" point -- due to FTS version being changed. -2: SELECT gp_wait_until_triggered_fault('vacuum_worker_changed', 3, dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; +2: SELECT gp_wait_until_triggered_fault('vacuum_worker_changed', 1, dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; -- now seg1's mirror is marked as down 2: SELECT content, role, preferred_role, mode, status FROM gp_segment_configuration WHERE content > -1; -- Resume execution and entering post_cleaup phase, suspend at the end of it. 2: SELECT gp_inject_fault('vacuum_ao_post_cleanup_end', 'suspend', dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; 2: SELECT gp_inject_fault('vacuum_worker_changed', 'reset', dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; -2: SELECT gp_wait_until_triggered_fault('vacuum_ao_post_cleanup_end', 3, dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; +2: SELECT gp_wait_until_triggered_fault('vacuum_ao_post_cleanup_end', 1, dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; -- The previous collected num_dead_tuples in compact phase is zero. select gp_segment_id, relid::regclass as relname, phase, heap_blks_total, heap_blks_scanned, heap_blks_vacuumed, index_vacuum_count, max_dead_tuples, num_dead_tuples from gp_stat_progress_vacuum where gp_segment_id > -1; @@ -180,6 +172,3 @@ select relid::regclass as relname, phase, heap_blks_total, heap_blks_scanned, he SELECT gp_inject_fault_infinite('all', 'reset', dbid) FROM gp_segment_configuration; reset Debug_appendonly_print_compaction; reset default_table_access_method; -ALTER SYSTEM RESET gp_fts_mark_mirror_down_grace_period; -ALTER SYSTEM RESET gp_fts_probe_interval; -SELECT gp_segment_id, pg_reload_conf() FROM gp_id UNION SELECT gp_segment_id, pg_reload_conf() FROM gp_dist_random('gp_id'); diff --git a/src/test/isolation2/sql/vacuum_progress_row.sql b/src/test/isolation2/sql/vacuum_progress_row.sql index 1ccf6ca090f..ec4b5a354db 100644 --- a/src/test/isolation2/sql/vacuum_progress_row.sql +++ b/src/test/isolation2/sql/vacuum_progress_row.sql @@ -11,16 +11,15 @@ CREATE TABLE vacuum_progress_ao_row(i int, j int); CREATE INDEX on vacuum_progress_ao_row(i); CREATE INDEX on vacuum_progress_ao_row(j); --- Insert all tuples to seg1 from two current sessions so that data are stored --- in two segment files. +-- Insert from two current sessions so that data are stored in two segment files. 1: BEGIN; 2: BEGIN; -1: INSERT INTO vacuum_progress_ao_row SELECT 0, i FROM generate_series(1, 100000) i; -2: INSERT INTO vacuum_progress_ao_row SELECT 0, i FROM generate_series(1, 100000) i; +1: INSERT INTO vacuum_progress_ao_row SELECT i, i FROM generate_series(1, 100000) i; +2: INSERT INTO vacuum_progress_ao_row SELECT i, i FROM generate_series(1, 100000) i; -- Commit so that the logical EOF of segno 2 is non-zero. 2: COMMIT; 2: BEGIN; -2: INSERT INTO vacuum_progress_ao_row SELECT 0, i FROM generate_series(1, 100000) i; +2: INSERT INTO vacuum_progress_ao_row SELECT i, i FROM generate_series(1, 100000) i; -- Abort so that segno 2 has dead tuples after its logical EOF 2: ABORT; 2q: @@ -30,157 +29,150 @@ CREATE INDEX on vacuum_progress_ao_row(j); -- Also delete half of the tuples evenly before the EOF of segno 2. DELETE FROM vacuum_progress_ao_row where j % 2 = 0; --- Lookup pg_class and collected stats view before VACUUM -SELECT relpages, reltuples, relallvisible FROM pg_class where relname = 'vacuum_progress_ao_row'; -SELECT n_live_tup, n_dead_tup, last_vacuum, vacuum_count FROM pg_stat_all_tables WHERE relname = 'vacuum_progress_ao_row'; - -- Perform VACUUM and observe the progress -- Suspend execution at pre-cleanup phase after truncating both segfiles to their logical EOF. -SELECT gp_inject_fault('appendonly_after_truncate_segment_file', 'suspend', '', '', '', 2, 2, 0, dbid) FROM gp_segment_configuration WHERE content = 1 AND role = 'p'; +SELECT gp_inject_fault('appendonly_after_truncate_segment_file', 'suspend', '', '', '', 2, 2, 0, dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; 1: set Debug_appendonly_print_compaction to on; 1&: VACUUM vacuum_progress_ao_row; SELECT gp_wait_until_triggered_fault('appendonly_after_truncate_segment_file', 2, dbid) FROM gp_segment_configuration WHERE content = 1 AND role = 'p'; -- We are in pre_cleanup phase and some blocks should've been vacuumed by now -1U: select relid::regclass as relname, phase, heap_blks_total, heap_blks_scanned, heap_blks_vacuumed, index_vacuum_count, max_dead_tuples, num_dead_tuples from pg_stat_progress_vacuum; +select relid::regclass as relname, phase, heap_blks_total, heap_blks_scanned, heap_blks_vacuumed, index_vacuum_count, max_dead_tuples, num_dead_tuples from gp_stat_progress_vacuum where gp_segment_id = 1; +select relid::regclass as relname, phase, heap_blks_total, heap_blks_scanned, heap_blks_vacuumed, index_vacuum_count, max_dead_tuples, num_dead_tuples from gp_stat_progress_vacuum_summary; -- Resume execution and suspend again in the middle of compact phase -SELECT gp_inject_fault('appendonly_insert', 'suspend', '', '', '', 200, 200, 0, dbid) FROM gp_segment_configuration WHERE content = 1 AND role = 'p'; -SELECT gp_inject_fault('appendonly_after_truncate_segment_file', 'reset', dbid) FROM gp_segment_configuration WHERE content = 1 AND role = 'p'; +SELECT gp_inject_fault('appendonly_insert', 'suspend', '', '', '', 200, 200, 0, dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; +SELECT gp_inject_fault('appendonly_after_truncate_segment_file', 'reset', dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; SELECT gp_wait_until_triggered_fault('appendonly_insert', 200, dbid) FROM gp_segment_configuration WHERE content = 1 AND role = 'p'; -- We are in compact phase. num_dead_tuples should increase as we move and count tuples, one by one. -1U: select relid::regclass as relname, phase, heap_blks_total, heap_blks_scanned, heap_blks_vacuumed, index_vacuum_count, max_dead_tuples, num_dead_tuples from pg_stat_progress_vacuum; +select relid::regclass as relname, phase, heap_blks_total, heap_blks_scanned, heap_blks_vacuumed, index_vacuum_count, max_dead_tuples, num_dead_tuples from gp_stat_progress_vacuum where gp_segment_id = 1; +select relid::regclass as relname, phase, heap_blks_total, heap_blks_scanned, heap_blks_vacuumed, index_vacuum_count, max_dead_tuples, num_dead_tuples from gp_stat_progress_vacuum_summary; -- Resume execution and suspend again after compacting all segfiles -SELECT gp_inject_fault('vacuum_ao_after_compact', 'suspend', dbid) FROM gp_segment_configuration WHERE content = 1 AND role = 'p'; -SELECT gp_inject_fault('appendonly_insert', 'reset', dbid) FROM gp_segment_configuration WHERE content = 1 AND role = 'p'; -SELECT gp_wait_until_triggered_fault('vacuum_ao_after_compact', 1, dbid) FROM gp_segment_configuration WHERE content = 1 AND role = 'p'; +SELECT gp_inject_fault('vacuum_ao_after_compact', 'suspend', dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; +SELECT gp_inject_fault('appendonly_insert', 'reset', dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; +SELECT gp_wait_until_triggered_fault('vacuum_ao_after_compact', 1, dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; -- After compacting all segfiles we expect 50000 dead tuples -1U: select relid::regclass as relname, phase, heap_blks_total, heap_blks_scanned, heap_blks_vacuumed, index_vacuum_count, max_dead_tuples, num_dead_tuples from pg_stat_progress_vacuum; +select relid::regclass as relname, phase, heap_blks_total, heap_blks_scanned, heap_blks_vacuumed, index_vacuum_count, max_dead_tuples, num_dead_tuples from gp_stat_progress_vacuum where gp_segment_id = 1; +select relid::regclass as relname, phase, heap_blks_total, heap_blks_scanned, heap_blks_vacuumed, index_vacuum_count, max_dead_tuples, num_dead_tuples from gp_stat_progress_vacuum_summary; -- Resume execution and entering post_cleaup phase, suspend at the end of it. -SELECT gp_inject_fault('vacuum_ao_post_cleanup_end', 'suspend', dbid) FROM gp_segment_configuration WHERE content = 1 AND role = 'p'; -SELECT gp_inject_fault('vacuum_ao_after_compact', 'reset', dbid) FROM gp_segment_configuration WHERE content = 1 AND role = 'p'; -SELECT gp_wait_until_triggered_fault('vacuum_ao_post_cleanup_end', 1, dbid) FROM gp_segment_configuration WHERE content = 1 AND role = 'p'; +SELECT gp_inject_fault('vacuum_ao_post_cleanup_end', 'suspend', dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; +SELECT gp_inject_fault('vacuum_ao_after_compact', 'reset', dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; +SELECT gp_wait_until_triggered_fault('vacuum_ao_post_cleanup_end', 1, dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; -- We should have skipped recycling the awaiting drop segment because the segment was still visible to the SELECT gp_wait_until_triggered_fault query. -1U: select relid::regclass as relname, phase, heap_blks_total, heap_blks_scanned, heap_blks_vacuumed, index_vacuum_count, max_dead_tuples, num_dead_tuples from pg_stat_progress_vacuum; -SELECT gp_inject_fault('vacuum_ao_post_cleanup_end', 'reset', dbid) FROM gp_segment_configuration WHERE content = 1 AND role = 'p'; +select relid::regclass as relname, phase, heap_blks_total, heap_blks_scanned, heap_blks_vacuumed, index_vacuum_count, max_dead_tuples, num_dead_tuples from gp_stat_progress_vacuum where gp_segment_id = 1; +select relid::regclass as relname, phase, heap_blks_total, heap_blks_scanned, heap_blks_vacuumed, index_vacuum_count, max_dead_tuples, num_dead_tuples from gp_stat_progress_vacuum_summary; + +SELECT gp_inject_fault('vacuum_ao_post_cleanup_end', 'reset', dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; 1<: -- pg_class and collected stats view should be updated after the 1st VACUUM 1U: SELECT wait_until_dead_tup_change_to('vacuum_progress_ao_row'::regclass::oid, 0); SELECT relpages, reltuples, relallvisible FROM pg_class where relname = 'vacuum_progress_ao_row'; -SELECT n_live_tup, n_dead_tup, last_vacuum is not null as has_last_vacuum, vacuum_count FROM pg_stat_all_tables WHERE relname = 'vacuum_progress_ao_row'; +SELECT n_live_tup, n_dead_tup, last_vacuum is not null as has_last_vacuum, vacuum_count FROM gp_stat_all_tables WHERE relname = 'vacuum_progress_ao_row' and gp_segment_id = 1; -- Perform VACUUM again to recycle the remaining awaiting drop segment marked by the previous run. -SELECT gp_inject_fault('vacuum_ao_after_index_delete', 'suspend', dbid) FROM gp_segment_configuration WHERE content = 1 AND role = 'p'; +SELECT gp_inject_fault('vacuum_ao_after_index_delete', 'suspend', dbid) FROM gp_segment_configuration WHERE content = 0 AND role = 'p'; +SELECT gp_inject_fault('appendonly_after_truncate_segment_file', 'suspend', dbid) FROM gp_segment_configuration WHERE content > 0 AND role = 'p'; 1&: VACUUM vacuum_progress_ao_row; --- Resume execution and entering pre_cleanup phase, suspend at vacuuming indexes. -SELECT gp_inject_fault('vacuum_ao_after_compact', 'reset', dbid) FROM gp_segment_configuration WHERE content = 1 AND role = 'p'; -SELECT gp_wait_until_triggered_fault('vacuum_ao_after_index_delete', 1, dbid) FROM gp_segment_configuration WHERE content = 1 AND role = 'p'; --- We are in vacuuming indexes phase (part of ao pre_cleanup phase), index_vacuum_count should increase to 1. -1U: select relid::regclass as relname, phase, heap_blks_total, heap_blks_scanned, heap_blks_vacuumed, index_vacuum_count, max_dead_tuples, num_dead_tuples from pg_stat_progress_vacuum; - --- Resume execution and moving on to truncate segments that were marked as AWAITING_DROP, there should be only 1. -SELECT gp_inject_fault('appendonly_after_truncate_segment_file', 'suspend', dbid) FROM gp_segment_configuration WHERE content = 1 AND role = 'p'; -SELECT gp_inject_fault('vacuum_ao_after_index_delete', 'reset', dbid) FROM gp_segment_configuration WHERE content = 1 AND role = 'p'; -SELECT gp_wait_until_triggered_fault('appendonly_after_truncate_segment_file', 1, dbid) FROM gp_segment_configuration WHERE content = 1 AND role = 'p'; --- We are in post_cleanup phase and should have truncated the old segfile. Both indexes should be vacuumed by now, and heap_blks_vacuumed should also increased -1U: select relid::regclass as relname, phase, heap_blks_total, heap_blks_scanned, heap_blks_vacuumed, index_vacuum_count, max_dead_tuples, num_dead_tuples from pg_stat_progress_vacuum; - -SELECT gp_inject_fault('appendonly_after_truncate_segment_file', 'reset', dbid) FROM gp_segment_configuration WHERE content = 1 AND role = 'p'; +-- Resume execution and entering pre_cleanup phase, suspend at vacuuming indexes for segment 0. +SELECT gp_wait_until_triggered_fault('vacuum_ao_after_index_delete', 1, dbid) FROM gp_segment_configuration WHERE content = 0 AND role = 'p'; +-- Resume execution and moving on to truncate segments that were marked as AWAITING_DROP for segment 1 and 2, there should be only 1. +SELECT gp_wait_until_triggered_fault('appendonly_after_truncate_segment_file', 1, dbid) FROM gp_segment_configuration WHERE content > 0 AND role = 'p'; +-- Segment 0 is in vacuuming indexes phase (part of ao pre_cleanup phase), index_vacuum_count should increase to 1. +select relid::regclass as relname, phase, heap_blks_total, heap_blks_scanned, heap_blks_vacuumed, index_vacuum_count, max_dead_tuples, num_dead_tuples from gp_stat_progress_vacuum where gp_segment_id = 0; +-- Segment 1 and 2 are in truncate segments phase (part of ao post_cleanup phase), heap_blks_vacuumed should increase to 1. +select relid::regclass as relname, phase, heap_blks_total, heap_blks_scanned, heap_blks_vacuumed, index_vacuum_count, max_dead_tuples, num_dead_tuples from gp_stat_progress_vacuum where gp_segment_id > 0; +select relid::regclass as relname, phase, heap_blks_total, heap_blks_scanned, heap_blks_vacuumed, index_vacuum_count, max_dead_tuples, num_dead_tuples from gp_stat_progress_vacuum_summary; + +SELECT gp_inject_fault('appendonly_after_truncate_segment_file', 'reset', dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; +SELECT gp_inject_fault('vacuum_ao_after_index_delete', 'reset', dbid) FROM gp_segment_configuration WHERE content = 0 AND role = 'p'; 1<: --- Vacuum has finished, nothing should show up in the progress view. -1U: select relid::regclass as relname, phase, heap_blks_total, heap_blks_scanned, heap_blks_vacuumed, index_vacuum_count, max_dead_tuples, num_dead_tuples from pg_stat_progress_vacuum; +-- Vacuum has finished, nothing should show up in the view. +select relid::regclass as relname, phase, heap_blks_total, heap_blks_scanned, heap_blks_vacuumed, index_vacuum_count, max_dead_tuples, num_dead_tuples from gp_stat_progress_vacuum where gp_segment_id = 1; +select relid::regclass as relname, phase, heap_blks_total, heap_blks_scanned, heap_blks_vacuumed, index_vacuum_count, max_dead_tuples, num_dead_tuples from gp_stat_progress_vacuum_summary; -- pg_class and collected stats view should be updated after the 2nd VACUUM -1U: SELECT wait_until_dead_tup_change_to('vacuum_progress_ao_row'::regclass::oid, 0); +1U: SELECT wait_until_vacuum_count_change_to('vacuum_progress_ao_row'::regclass::oid, 2); SELECT relpages, reltuples, relallvisible FROM pg_class where relname = 'vacuum_progress_ao_row'; -SELECT n_live_tup, n_dead_tup, last_vacuum is not null as has_last_vacuum, vacuum_count FROM pg_stat_all_tables WHERE relname = 'vacuum_progress_ao_row'; - --- open if system views gp_stat_progress_vacuum* are enabled ---1q: ----- Test vacuum worker process is changed at post-cleanup phase due to mirror down. ----- Current behavior is it will clear previous compact phase num_dead_tuples in post-cleanup ----- phase (at injecting point vacuum_ao_post_cleanup_end), which is different from above case ----- in which vacuum worker isn't changed. ---ALTER SYSTEM SET gp_fts_mark_mirror_down_grace_period to 10; ---ALTER SYSTEM SET gp_fts_probe_interval to 10; ---SELECT gp_segment_id, pg_reload_conf() FROM gp_id UNION SELECT gp_segment_id, pg_reload_conf() FROM gp_dist_random('gp_id'); --- ---DROP TABLE IF EXISTS vacuum_progress_ao_row; ---CREATE TABLE vacuum_progress_ao_row(i int, j int); ---CREATE INDEX on vacuum_progress_ao_row(i); ---CREATE INDEX on vacuum_progress_ao_row(j); ---1: BEGIN; ---2: BEGIN; ---1: INSERT INTO vacuum_progress_ao_row SELECT i, i FROM generate_series(1, 100000) i; ---2: INSERT INTO vacuum_progress_ao_row SELECT i, i FROM generate_series(1, 100000) i; ---2: COMMIT; ---2: BEGIN; ---2: INSERT INTO vacuum_progress_ao_row SELECT i, i FROM generate_series(1, 100000) i; ---2: ABORT; ---2q: ---1: ABORT; ---DELETE FROM vacuum_progress_ao_row where j % 2 = 0; --- ----- Suspend execution at the end of compact phase. ---2: SELECT gp_inject_fault('vacuum_ao_after_compact', 'suspend', dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; --- ---1: set debug_appendonly_print_compaction to on; ---1&: vacuum vacuum_progress_ao_row; --- ---2: SELECT gp_wait_until_triggered_fault('vacuum_ao_after_compact', 3, dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; --- ----- Non-zero progressing data num_dead_tuples is showed up. ---select gp_segment_id, relid::regclass as relname, phase, heap_blks_total, heap_blks_scanned, heap_blks_vacuumed, index_vacuum_count, max_dead_tuples, num_dead_tuples from gp_stat_progress_vacuum where gp_segment_id > -1; ---select relid::regclass as relname, phase, heap_blks_total, heap_blks_scanned, heap_blks_vacuumed, index_vacuum_count, max_dead_tuples, num_dead_tuples from gp_stat_progress_vacuum_summary; --- ----- Resume execution of compact phase and block at syncrep. ---2: SELECT gp_inject_fault_infinite('wal_sender_loop', 'suspend', dbid) FROM gp_segment_configuration WHERE role = 'p' and content = 1; ---2: SELECT gp_inject_fault('vacuum_ao_after_compact', 'reset', dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; ----- stop the mirror should turn off syncrep ---2: SELECT pg_ctl(datadir, 'stop', 'immediate') FROM gp_segment_configuration WHERE content=1 AND role = 'm'; --- ----- Resume walsender to detect mirror down and suspend at the beginning ----- of post-cleanup taken over by a new vacuum worker. ---2: SELECT gp_inject_fault('vacuum_worker_changed', 'suspend', dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; ----- resume walsender and let it exit so that mirror stop can be detected ---2: SELECT gp_inject_fault_infinite('wal_sender_loop', 'reset', dbid) FROM gp_segment_configuration WHERE role = 'p' and content = 1; ----- Ensure we enter into the target logic which stops cumulative data but ----- initializes a new vacrelstats at the beginning of post-cleanup phase. ----- Also all segments should reach to the same "vacuum_worker_changed" point ----- due to FTS version being changed. ---2: SELECT gp_wait_until_triggered_fault('vacuum_worker_changed', 1, dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; ----- now seg1's mirror is marked as down ---2: SELECT content, role, preferred_role, mode, status FROM gp_segment_configuration WHERE content > -1; --- ----- Resume execution and entering post_cleaup phase, suspend at the end of it. ---2: SELECT gp_inject_fault('vacuum_ao_post_cleanup_end', 'suspend', dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; ---2: SELECT gp_inject_fault('vacuum_worker_changed', 'reset', dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; ---2: SELECT gp_wait_until_triggered_fault('vacuum_ao_post_cleanup_end', 1, dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; --- ----- The previous collected num_dead_tuples in compact phase is zero. ---select gp_segment_id, relid::regclass as relname, phase, heap_blks_total, heap_blks_scanned, heap_blks_vacuumed, index_vacuum_count, max_dead_tuples, num_dead_tuples from gp_stat_progress_vacuum where gp_segment_id > -1; ---select relid::regclass as relname, phase, heap_blks_total, heap_blks_scanned, heap_blks_vacuumed, index_vacuum_count, max_dead_tuples, num_dead_tuples from gp_stat_progress_vacuum_summary; --- ---2: SELECT gp_inject_fault('vacuum_ao_post_cleanup_end', 'reset', dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; --- ---1<: --- ----- restore environment ---1: reset debug_appendonly_print_compaction; --- ---2: SELECT pg_ctl_start(datadir, port) FROM gp_segment_configuration WHERE role = 'm' AND content = 1; ---2: SELECT wait_until_all_segments_synchronized(); --- ----- Cleanup ---SELECT gp_inject_fault_infinite('all', 'reset', dbid) FROM gp_segment_configuration; ---reset Debug_appendonly_print_compaction; ---reset default_table_access_method; ---ALTER SYSTEM RESET gp_fts_mark_mirror_down_grace_period; ---ALTER SYSTEM RESET gp_fts_probe_interval; ---SELECT gp_segment_id, pg_reload_conf() FROM gp_id UNION SELECT gp_segment_id, pg_reload_conf() FROM gp_dist_random('gp_id'); --- \ No newline at end of file +SELECT n_live_tup, n_dead_tup, last_vacuum is not null as has_last_vacuum, vacuum_count FROM gp_stat_all_tables WHERE relname = 'vacuum_progress_ao_row' and gp_segment_id = 1; +SELECT n_live_tup, n_dead_tup, last_vacuum is not null as has_last_vacuum, vacuum_count FROM gp_stat_all_tables_summary WHERE relname = 'vacuum_progress_ao_row'; + +1q: +-- Test vacuum worker process is changed at post-cleanup phase due to mirror down. +-- Current behavior is it will clear previous compact phase num_dead_tuples in post-cleanup +-- phase (at injecting point vacuum_ao_post_cleanup_end), which is different from above case +-- in which vacuum worker isn't changed. +DROP TABLE IF EXISTS vacuum_progress_ao_row; +CREATE TABLE vacuum_progress_ao_row(i int, j int); +CREATE INDEX on vacuum_progress_ao_row(i); +CREATE INDEX on vacuum_progress_ao_row(j); +1: BEGIN; +2: BEGIN; +1: INSERT INTO vacuum_progress_ao_row SELECT i, i FROM generate_series(1, 100000) i; +2: INSERT INTO vacuum_progress_ao_row SELECT i, i FROM generate_series(1, 100000) i; +2: COMMIT; +2: BEGIN; +2: INSERT INTO vacuum_progress_ao_row SELECT i, i FROM generate_series(1, 100000) i; +2: ABORT; +2q: +1: ABORT; +DELETE FROM vacuum_progress_ao_row where j % 2 = 0; + +-- Suspend execution at the end of compact phase. +2: SELECT gp_inject_fault('vacuum_ao_after_compact', 'suspend', dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; + +1: set debug_appendonly_print_compaction to on; +1&: vacuum vacuum_progress_ao_row; + +2: SELECT gp_wait_until_triggered_fault('vacuum_ao_after_compact', 1, dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; + +-- Non-zero progressing data num_dead_tuples is showed up. +select gp_segment_id, relid::regclass as relname, phase, heap_blks_total, heap_blks_scanned, heap_blks_vacuumed, index_vacuum_count, max_dead_tuples, num_dead_tuples from gp_stat_progress_vacuum where gp_segment_id > -1; +select relid::regclass as relname, phase, heap_blks_total, heap_blks_scanned, heap_blks_vacuumed, index_vacuum_count, max_dead_tuples, num_dead_tuples from gp_stat_progress_vacuum_summary; + +-- Resume execution of compact phase and block at syncrep. +2: SELECT gp_inject_fault_infinite('wal_sender_loop', 'suspend', dbid) FROM gp_segment_configuration WHERE role = 'p' and content = 1; +2: SELECT gp_inject_fault('vacuum_ao_after_compact', 'reset', dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; +-- stop the mirror should turn off syncrep +2: SELECT pg_ctl(datadir, 'stop', 'immediate') FROM gp_segment_configuration WHERE content=1 AND role = 'm'; + +-- Resume walsender to detect mirror down and suspend at the beginning +-- of post-cleanup taken over by a new vacuum worker. +2: SELECT gp_inject_fault('vacuum_worker_changed', 'suspend', dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; +-- resume walsender and let it exit so that mirror stop can be detected +2: SELECT gp_inject_fault_infinite('wal_sender_loop', 'reset', dbid) FROM gp_segment_configuration WHERE role = 'p' and content = 1; +-- Ensure we enter into the target logic which stops cumulative data but +-- initializes a new vacrelstats at the beginning of post-cleanup phase. +-- Also all segments should reach to the same "vacuum_worker_changed" point +-- due to FTS version being changed. +2: SELECT gp_wait_until_triggered_fault('vacuum_worker_changed', 1, dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; +-- now seg1's mirror is marked as down +2: SELECT content, role, preferred_role, mode, status FROM gp_segment_configuration WHERE content > -1; + +-- Resume execution and entering post_cleaup phase, suspend at the end of it. +2: SELECT gp_inject_fault('vacuum_ao_post_cleanup_end', 'suspend', dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; +2: SELECT gp_inject_fault('vacuum_worker_changed', 'reset', dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; +2: SELECT gp_wait_until_triggered_fault('vacuum_ao_post_cleanup_end', 1, dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; + +-- The previous collected num_dead_tuples in compact phase is zero. +select gp_segment_id, relid::regclass as relname, phase, heap_blks_total, heap_blks_scanned, heap_blks_vacuumed, index_vacuum_count, max_dead_tuples, num_dead_tuples from gp_stat_progress_vacuum where gp_segment_id > -1; +select relid::regclass as relname, phase, heap_blks_total, heap_blks_scanned, heap_blks_vacuumed, index_vacuum_count, max_dead_tuples, num_dead_tuples from gp_stat_progress_vacuum_summary; + +2: SELECT gp_inject_fault('vacuum_ao_post_cleanup_end', 'reset', dbid) FROM gp_segment_configuration WHERE content > -1 AND role = 'p'; + +1<: + +-- restore environment +1: reset debug_appendonly_print_compaction; + +2: SELECT pg_ctl_start(datadir, port) FROM gp_segment_configuration WHERE role = 'm' AND content = 1; +2: SELECT wait_until_all_segments_synchronized(); + +-- Cleanup +SELECT gp_inject_fault_infinite('all', 'reset', dbid) FROM gp_segment_configuration; +reset Debug_appendonly_print_compaction; +reset default_table_access_method; diff --git a/src/test/regress/expected/pg_stat.out b/src/test/regress/expected/pg_stat.out index 80e4e4ff132..d202ca7090c 100644 --- a/src/test/regress/expected/pg_stat.out +++ b/src/test/regress/expected/pg_stat.out @@ -5,7 +5,7 @@ create table pg_stat_test(a int); select schemaname, relname, seq_scan, seq_tup_read, idx_scan, idx_tup_fetch, n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup -from pg_stat_all_tables where relname = 'pg_stat_test'; +from gp_stat_all_tables_summary where relname = 'pg_stat_test'; schemaname | relname | seq_scan | seq_tup_read | idx_scan | idx_tup_fetch | n_tup_ins | n_tup_upd | n_tup_del | n_tup_hot_upd | n_live_tup | n_dead_tup ------------+--------------+----------+--------------+----------+---------------+-----------+-----------+-----------+---------------+------------+------------ public | pg_stat_test | 0 | 0 | | | 0 | 0 | 0 | 0 | 0 | 0 @@ -14,7 +14,7 @@ from pg_stat_all_tables where relname = 'pg_stat_test'; select schemaname, relname, seq_scan, seq_tup_read, idx_scan, idx_tup_fetch, n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup -from pg_stat_user_tables where relname = 'pg_stat_test'; +from gp_stat_user_tables_summary where relname = 'pg_stat_test'; schemaname | relname | seq_scan | seq_tup_read | idx_scan | idx_tup_fetch | n_tup_ins | n_tup_upd | n_tup_del | n_tup_hot_upd | n_live_tup | n_dead_tup ------------+--------------+----------+--------------+----------+---------------+-----------+-----------+-----------+---------------+------------+------------ public | pg_stat_test | 0 | 0 | | | 0 | 0 | 0 | 0 | 0 | 0 @@ -22,14 +22,14 @@ from pg_stat_user_tables where relname = 'pg_stat_test'; select schemaname, relname, indexrelname, idx_scan, idx_tup_read, idx_tup_fetch -from pg_stat_all_indexes where relname = 'pg_stat_test'; +from gp_stat_all_indexes_summary where relname = 'pg_stat_test'; schemaname | relname | indexrelname | idx_scan | idx_tup_read | idx_tup_fetch ------------+---------+--------------+----------+--------------+--------------- (0 rows) select schemaname, relname, indexrelname, idx_scan, idx_tup_read, idx_tup_fetch -from pg_stat_user_indexes where relname = 'pg_stat_test'; +from gp_stat_user_indexes_summary where relname = 'pg_stat_test'; schemaname | relname | indexrelname | idx_scan | idx_tup_read | idx_tup_fetch ------------+---------+--------------+----------+--------------+--------------- (0 rows) @@ -60,10 +60,16 @@ select * from pg_stat_test where a = 1; (0 rows) reset enable_seqscan; +select gp_stat_force_next_flush(); + gp_stat_force_next_flush +-------------------------- + +(1 row) + select schemaname, relname, seq_scan, seq_tup_read, idx_scan, idx_tup_fetch, n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze -from pg_stat_all_tables where relname = 'pg_stat_test'; +from gp_stat_all_tables_summary where relname = 'pg_stat_test'; schemaname | relname | seq_scan | seq_tup_read | idx_scan | idx_tup_fetch | n_tup_ins | n_tup_upd | n_tup_del | n_tup_hot_upd | n_live_tup | n_dead_tup | n_mod_since_analyze ------------+--------------+----------+--------------+----------+---------------+-----------+-----------+-----------+---------------+------------+------------+--------------------- public | pg_stat_test | 12 | 391 | 1 | 0 | 110 | 0 | 19 | 0 | 91 | 19 | 129 @@ -72,7 +78,7 @@ from pg_stat_all_tables where relname = 'pg_stat_test'; select schemaname, relname, seq_scan, seq_tup_read, idx_scan, idx_tup_fetch, n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze -from pg_stat_user_tables where relname = 'pg_stat_test'; +from gp_stat_user_tables_summary where relname = 'pg_stat_test'; schemaname | relname | seq_scan | seq_tup_read | idx_scan | idx_tup_fetch | n_tup_ins | n_tup_upd | n_tup_del | n_tup_hot_upd | n_live_tup | n_dead_tup | n_mod_since_analyze ------------+--------------+----------+--------------+----------+---------------+-----------+-----------+-----------+---------------+------------+------------+--------------------- public | pg_stat_test | 12 | 391 | 1 | 0 | 110 | 0 | 19 | 0 | 91 | 19 | 129 @@ -80,7 +86,7 @@ from pg_stat_user_tables where relname = 'pg_stat_test'; select schemaname, relname, indexrelname, idx_scan, idx_tup_read, idx_tup_fetch -from pg_stat_all_indexes where relname = 'pg_stat_test'; +from gp_stat_all_indexes_summary where relname = 'pg_stat_test'; schemaname | relname | indexrelname | idx_scan | idx_tup_read | idx_tup_fetch ------------+--------------+--------------------------+----------+--------------+--------------- public | pg_stat_test | pg_stat_user_table_index | 1 | 1 | 0 @@ -88,7 +94,7 @@ from pg_stat_all_indexes where relname = 'pg_stat_test'; select schemaname, relname, indexrelname, idx_scan, idx_tup_read, idx_tup_fetch -from pg_stat_user_indexes where relname = 'pg_stat_test'; +from gp_stat_user_indexes_summary where relname = 'pg_stat_test'; schemaname | relname | indexrelname | idx_scan | idx_tup_read | idx_tup_fetch ------------+--------------+--------------------------+----------+--------------+--------------- public | pg_stat_test | pg_stat_user_table_index | 1 | 1 | 0 diff --git a/src/test/regress/expected/pgstat_qd_tabstat.out b/src/test/regress/expected/pgstat_qd_tabstat.out index ca612e18b9c..bbac9a662a4 100644 --- a/src/test/regress/expected/pgstat_qd_tabstat.out +++ b/src/test/regress/expected/pgstat_qd_tabstat.out @@ -4,13 +4,13 @@ set gp_autostats_mode = none; -- Test pgstat table stat for copy on QD create table table_for_docopy(i int, j varchar) distributed by (i); copy table_for_docopy (i, j) from stdin; -select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. - pg_sleep ----------- +select gp_stat_force_next_flush(); + gp_stat_force_next_flush +-------------------------- (1 row) -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'table_for_docopy'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from gp_stat_all_tables_summary where relid = 'table_for_docopy'::regclass; n_tup_ins | n_tup_upd | n_tup_del | n_tup_hot_upd | n_live_tup | n_dead_tup | n_mod_since_analyze -----------+-----------+-----------+---------------+------------+------------+--------------------- 3 | 0 | 0 | 0 | 3 | 0 | 3 @@ -26,13 +26,13 @@ create table copy_on_segment (a int,b char); NOTICE: Table doesn't have 'DISTRIBUTED BY' clause -- Using column named 'a' as the Apache Cloudberry data distribution key for this table. HINT: The 'DISTRIBUTED BY' clause determines the distribution of data. Make sure column(s) chosen are the optimal data distribution key to minimize skew. COPY copy_on_segment from '/tmp/data_tbl.csv' on segment log errors segment reject limit 3 rows; -select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. - pg_sleep ----------- +select gp_stat_force_next_flush(); + gp_stat_force_next_flush +-------------------------- (1 row) -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'copy_on_segment'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from gp_stat_all_tables_summary where relid = 'copy_on_segment'::regclass; n_tup_ins | n_tup_upd | n_tup_del | n_tup_hot_upd | n_live_tup | n_dead_tup | n_mod_since_analyze -----------+-----------+-----------+---------------+------------+------------+--------------------- 4 | 0 | 0 | 0 | 4 | 0 | 4 @@ -64,13 +64,13 @@ with updated AS (update table_for_initplan set k = 33 where i = 3 returning k) s 1 | test1 | 1 | 33 (3 rows) -select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. - pg_sleep ----------- +select gp_stat_force_next_flush(); + gp_stat_force_next_flush +-------------------------- (1 row) -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'table_for_initplan'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from gp_stat_all_tables_summary where relid = 'table_for_initplan'::regclass; n_tup_ins | n_tup_upd | n_tup_del | n_tup_hot_upd | n_live_tup | n_dead_tup | n_mod_since_analyze -----------+-----------+-----------+---------------+------------+------------+--------------------- 3 | 1 | 0 | 0 | 3 | 1 | 4 @@ -80,13 +80,13 @@ select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n create table table_for_ctas with (autovacuum_enabled=false) as select i, 'hello' || i from generate_series(1, 100) f(i); NOTICE: Table doesn't have 'DISTRIBUTED BY' clause -- Using column(s) named 'i' as the Apache Cloudberry data distribution key for this table. HINT: The 'DISTRIBUTED BY' clause determines the distribution of data. Make sure column(s) chosen are the optimal data distribution key to minimize skew. -select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. - pg_sleep ----------- +select gp_stat_force_next_flush(); + gp_stat_force_next_flush +-------------------------- (1 row) -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'table_for_ctas'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from gp_stat_all_tables_summary where relid = 'table_for_ctas'::regclass; n_tup_ins | n_tup_upd | n_tup_del | n_tup_hot_upd | n_live_tup | n_dead_tup | n_mod_since_analyze -----------+-----------+-----------+---------------+------------+------------+--------------------- 100 | 0 | 0 | 0 | 100 | 0 | 100 @@ -95,13 +95,13 @@ select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n select i, 'hello' || i into table_for_insert_into from generate_series(1, 100) f(i); NOTICE: Table doesn't have 'DISTRIBUTED BY' clause -- Using column(s) named 'i' as the Apache Cloudberry data distribution key for this table. HINT: The 'DISTRIBUTED BY' clause determines the distribution of data. Make sure column(s) chosen are the optimal data distribution key to minimize skew. -select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. - pg_sleep ----------- +select gp_stat_force_next_flush(); + gp_stat_force_next_flush +-------------------------- (1 row) -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'table_for_insert_into'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from gp_stat_all_tables_summary where relid = 'table_for_insert_into'::regclass; n_tup_ins | n_tup_upd | n_tup_del | n_tup_hot_upd | n_live_tup | n_dead_tup | n_mod_since_analyze -----------+-----------+-----------+---------------+------------+------------+--------------------- 100 | 0 | 0 | 0 | 100 | 0 | 100 @@ -110,26 +110,26 @@ select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n -- Test pgstat table stat in ALTER TABLE SET DISTRIBUTED BY on QD create table table_for_set_distributed_by(i int, j varchar) distributed by (i); insert into table_for_set_distributed_by select i, 'hello' || i from generate_series(1, 333) f(i); -select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. - pg_sleep ----------- +select gp_stat_force_next_flush(); + gp_stat_force_next_flush +-------------------------- (1 row) -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'table_for_set_distributed_by'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from gp_stat_all_tables_summary where relid = 'table_for_set_distributed_by'::regclass; n_tup_ins | n_tup_upd | n_tup_del | n_tup_hot_upd | n_live_tup | n_dead_tup | n_mod_since_analyze -----------+-----------+-----------+---------------+------------+------------+--------------------- 333 | 0 | 0 | 0 | 333 | 0 | 333 (1 row) alter table table_for_set_distributed_by set distributed by (j); -select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. - pg_sleep ----------- +select gp_stat_force_next_flush(); + gp_stat_force_next_flush +-------------------------- (1 row) -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'table_for_set_distributed_by'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from gp_stat_all_tables_summary where relid = 'table_for_set_distributed_by'::regclass; n_tup_ins | n_tup_upd | n_tup_del | n_tup_hot_upd | n_live_tup | n_dead_tup | n_mod_since_analyze -----------+-----------+-----------+---------------+------------+------------+--------------------- 333 | 0 | 0 | 0 | 333 | 0 | 333 @@ -151,13 +151,13 @@ select update_table_for_function(); (1 row) -select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. - pg_sleep ----------- +select gp_stat_force_next_flush(); + gp_stat_force_next_flush +-------------------------- (1 row) -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'table_for_function'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from gp_stat_all_tables_summary where relid = 'table_for_function'::regclass; n_tup_ins | n_tup_upd | n_tup_del | n_tup_hot_upd | n_live_tup | n_dead_tup | n_mod_since_analyze -----------+-----------+-----------+---------------+------------+------------+--------------------- 333 | 0 | 200 | 0 | 133 | 200 | 533 @@ -179,13 +179,13 @@ select count(distinct gp_segment_id) from table_for_expand; 1 (1 row) -select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. - pg_sleep ----------- +select gp_stat_force_next_flush(); + gp_stat_force_next_flush +-------------------------- (1 row) -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'table_for_expand'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from gp_stat_all_tables_summary where relid = 'table_for_expand'::regclass; n_tup_ins | n_tup_upd | n_tup_del | n_tup_hot_upd | n_live_tup | n_dead_tup | n_mod_since_analyze -----------+-----------+-----------+---------------+------------+------------+--------------------- 333 | 0 | 0 | 0 | 333 | 0 | 333 @@ -198,13 +198,13 @@ select count(distinct gp_segment_id) from table_for_expand; 3 (1 row) -select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. - pg_sleep ----------- +select gp_stat_force_next_flush(); + gp_stat_force_next_flush +-------------------------- (1 row) -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'table_for_expand'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from gp_stat_all_tables_summary where relid = 'table_for_expand'::regclass; n_tup_ins | n_tup_upd | n_tup_del | n_tup_hot_upd | n_live_tup | n_dead_tup | n_mod_since_analyze -----------+-----------+-----------+---------------+------------+------------+--------------------- 333 | 0 | 0 | 0 | 333 | 0 | 333 @@ -232,13 +232,13 @@ rollback to savepoint level5; update table_for_iud set j = 'heroes never die' where i >= 300; release savepoint level3; commit; -select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. - pg_sleep ----------- +select gp_stat_force_next_flush(); + gp_stat_force_next_flush +-------------------------- (1 row) -select n_live_tup, n_dead_tup from pg_stat_all_tables_internal where relid = 'table_for_iud'::regclass; +select n_live_tup, n_dead_tup from gp_stat_all_tables_summary where relid = 'table_for_iud'::regclass; n_live_tup | n_dead_tup ------------+------------ 333 | 34 @@ -258,13 +258,13 @@ update table_for_iud set j = 'are you ok' where i >= 300; rollback to savepoint level3; delete from table_for_iud where i <= 200; commit; -select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. - pg_sleep ----------- +select gp_stat_force_next_flush(); + gp_stat_force_next_flush +-------------------------- (1 row) -select n_live_tup, n_dead_tup from pg_stat_all_tables_internal where relid = 'table_for_iud'::regclass; +select n_live_tup, n_dead_tup from gp_stat_all_tables_summary where relid = 'table_for_iud'::regclass; n_live_tup | n_dead_tup ------------+------------ 133 | 713 @@ -273,13 +273,13 @@ select n_live_tup, n_dead_tup from pg_stat_all_tables_internal where relid = 'ta -- Test pgstat table stat in TRUNCATE on QD create table table_for_truncate(i int, j varchar) distributed by (i); insert into table_for_truncate select i, 'hello' || i from generate_series(1, 777) f(i); -select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. - pg_sleep ----------- +select gp_stat_force_next_flush(); + gp_stat_force_next_flush +-------------------------- (1 row) -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'table_for_truncate'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from gp_stat_all_tables_summary where relid = 'table_for_truncate'::regclass; n_tup_ins | n_tup_upd | n_tup_del | n_tup_hot_upd | n_live_tup | n_dead_tup | n_mod_since_analyze -----------+-----------+-----------+---------------+------------+------------+--------------------- 777 | 0 | 0 | 0 | 777 | 0 | 777 @@ -297,13 +297,13 @@ insert into table_for_truncate select i, 'hello' || i from generate_series(1, 80 delete from table_for_truncate where i >= 700; update table_for_truncate set j = 'D' where i <= 200; commit; -select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. - pg_sleep ----------- +select gp_stat_force_next_flush(); + gp_stat_force_next_flush +-------------------------- (1 row) -select n_live_tup, n_dead_tup from pg_stat_all_tables_internal where relid = 'table_for_truncate'::regclass; +select n_live_tup, n_dead_tup from gp_stat_all_tables_summary where relid = 'table_for_truncate'::regclass; n_live_tup | n_dead_tup ------------+------------ 699 | 301 @@ -311,13 +311,13 @@ select n_live_tup, n_dead_tup from pg_stat_all_tables_internal where relid = 'ta create table table_for_truncate_abort(i int, j varchar) distributed by (i); insert into table_for_truncate_abort select i, 'hello' || i from generate_series(1, 777) f(i); -select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. - pg_sleep ----------- +select gp_stat_force_next_flush(); + gp_stat_force_next_flush +-------------------------- (1 row) -select n_live_tup, n_dead_tup from pg_stat_all_tables_internal where relid = 'table_for_truncate_abort'::regclass; +select n_live_tup, n_dead_tup from gp_stat_all_tables_summary where relid = 'table_for_truncate_abort'::regclass; n_live_tup | n_dead_tup ------------+------------ 777 | 0 @@ -335,13 +335,13 @@ insert into table_for_truncate_abort select i, 'hello' || i from generate_series delete from table_for_truncate_abort where i < 700; update table_for_truncate_abort set j = 'D' where i >= 200; rollback; -select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. - pg_sleep ----------- +select gp_stat_force_next_flush(); + gp_stat_force_next_flush +-------------------------- (1 row) -select n_live_tup, n_dead_tup from pg_stat_all_tables_internal where relid = 'table_for_truncate_abort'::regclass; +select n_live_tup, n_dead_tup from gp_stat_all_tables_summary where relid = 'table_for_truncate_abort'::regclass; n_live_tup | n_dead_tup ------------+------------ 777 | 223 @@ -354,25 +354,25 @@ PARTITION BY RANGE (rank) ( START (1) END (10) EVERY (5), DEFAULT PARTITION extra ); insert into rankpart select i, i % 10, i from generate_series(1, 1000)i; -select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. - pg_sleep ----------- +select gp_stat_force_next_flush(); + gp_stat_force_next_flush +-------------------------- (1 row) -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'rankpart_1_prt_2'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from gp_stat_all_tables_summary where relid = 'rankpart_1_prt_2'::regclass; n_tup_ins | n_tup_upd | n_tup_del | n_tup_hot_upd | n_live_tup | n_dead_tup | n_mod_since_analyze -----------+-----------+-----------+---------------+------------+------------+--------------------- 500 | 0 | 0 | 0 | 500 | 0 | 500 (1 row) -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'rankpart_1_prt_3'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from gp_stat_all_tables_summary where relid = 'rankpart_1_prt_3'::regclass; n_tup_ins | n_tup_upd | n_tup_del | n_tup_hot_upd | n_live_tup | n_dead_tup | n_mod_since_analyze -----------+-----------+-----------+---------------+------------+------------+--------------------- 400 | 0 | 0 | 0 | 400 | 0 | 400 (1 row) -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'rankpart_1_prt_extra'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from gp_stat_all_tables_summary where relid = 'rankpart_1_prt_extra'::regclass; n_tup_ins | n_tup_upd | n_tup_del | n_tup_hot_upd | n_live_tup | n_dead_tup | n_mod_since_analyze -----------+-----------+-----------+---------------+------------+------------+--------------------- 100 | 0 | 0 | 0 | 100 | 0 | 100 @@ -381,44 +381,44 @@ select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n begin; delete from rankpart where id <= 100; rollback; -select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. - pg_sleep ----------- +select gp_stat_force_next_flush(); + gp_stat_force_next_flush +-------------------------- (1 row) -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'rankpart_1_prt_2'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from gp_stat_all_tables_summary where relid = 'rankpart_1_prt_2'::regclass; n_tup_ins | n_tup_upd | n_tup_del | n_tup_hot_upd | n_live_tup | n_dead_tup | n_mod_since_analyze -----------+-----------+-----------+---------------+------------+------------+--------------------- 500 | 0 | 50 | 0 | 500 | 0 | 500 (1 row) -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'rankpart_1_prt_3'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from gp_stat_all_tables_summary where relid = 'rankpart_1_prt_3'::regclass; n_tup_ins | n_tup_upd | n_tup_del | n_tup_hot_upd | n_live_tup | n_dead_tup | n_mod_since_analyze -----------+-----------+-----------+---------------+------------+------------+--------------------- 400 | 0 | 40 | 0 | 400 | 0 | 400 (1 row) -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'rankpart_1_prt_extra'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from gp_stat_all_tables_summary where relid = 'rankpart_1_prt_extra'::regclass; n_tup_ins | n_tup_upd | n_tup_del | n_tup_hot_upd | n_live_tup | n_dead_tup | n_mod_since_analyze -----------+-----------+-----------+---------------+------------+------------+--------------------- 100 | 0 | 10 | 0 | 100 | 0 | 100 (1 row) copy rankpart (id, rank, product) from stdin; -select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. - pg_sleep ----------- +select gp_stat_force_next_flush(); + gp_stat_force_next_flush +-------------------------- (1 row) -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'rankpart_1_prt_2'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from gp_stat_all_tables_summary where relid = 'rankpart_1_prt_2'::regclass; n_tup_ins | n_tup_upd | n_tup_del | n_tup_hot_upd | n_live_tup | n_dead_tup | n_mod_since_analyze -----------+-----------+-----------+---------------+------------+------------+--------------------- 505 | 0 | 50 | 0 | 505 | 0 | 505 (1 row) -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'rankpart_1_prt_3'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from gp_stat_all_tables_summary where relid = 'rankpart_1_prt_3'::regclass; n_tup_ins | n_tup_upd | n_tup_del | n_tup_hot_upd | n_live_tup | n_dead_tup | n_mod_since_analyze -----------+-----------+-----------+---------------+------------+------------+--------------------- 405 | 0 | 40 | 0 | 405 | 0 | 405 @@ -433,25 +433,25 @@ delete from rankpart where id > 1005; release savepoint level2; rollback to savepoint level1; commit; -select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. - pg_sleep ----------- +select gp_stat_force_next_flush(); + gp_stat_force_next_flush +-------------------------- (1 row) -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'rankpart_1_prt_2'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from gp_stat_all_tables_summary where relid = 'rankpart_1_prt_2'::regclass; n_tup_ins | n_tup_upd | n_tup_del | n_tup_hot_upd | n_live_tup | n_dead_tup | n_mod_since_analyze -----------+-----------+-----------+---------------+------------+------------+--------------------- 510 | 0 | 55 | 0 | 510 | 0 | 510 (1 row) -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'rankpart_1_prt_3'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from gp_stat_all_tables_summary where relid = 'rankpart_1_prt_3'::regclass; n_tup_ins | n_tup_upd | n_tup_del | n_tup_hot_upd | n_live_tup | n_dead_tup | n_mod_since_analyze -----------+-----------+-----------+---------------+------------+------------+--------------------- 410 | 0 | 50 | 0 | 400 | 10 | 410 (1 row) -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'rankpart_1_prt_extra'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from gp_stat_all_tables_summary where relid = 'rankpart_1_prt_extra'::regclass; n_tup_ins | n_tup_upd | n_tup_del | n_tup_hot_upd | n_live_tup | n_dead_tup | n_mod_since_analyze -----------+-----------+-----------+---------------+------------+------------+--------------------- 100 | 0 | 10 | 0 | 100 | 0 | 100 @@ -462,25 +462,25 @@ savepoint level1_1; insert into rankpart select i, i % 10, i from generate_series(2001, 3000)i; insert into rankpart select i, i % 10, i from generate_series(3001, 4000)i; commit; -select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. - pg_sleep ----------- +select gp_stat_force_next_flush(); + gp_stat_force_next_flush +-------------------------- (1 row) -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'rankpart_1_prt_2'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from gp_stat_all_tables_summary where relid = 'rankpart_1_prt_2'::regclass; n_tup_ins | n_tup_upd | n_tup_del | n_tup_hot_upd | n_live_tup | n_dead_tup | n_mod_since_analyze -----------+-----------+-----------+---------------+------------+------------+--------------------- 1510 | 0 | 55 | 0 | 1510 | 0 | 1510 (1 row) -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'rankpart_1_prt_3'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from gp_stat_all_tables_summary where relid = 'rankpart_1_prt_3'::regclass; n_tup_ins | n_tup_upd | n_tup_del | n_tup_hot_upd | n_live_tup | n_dead_tup | n_mod_since_analyze -----------+-----------+-----------+---------------+------------+------------+--------------------- 1210 | 0 | 50 | 0 | 1200 | 10 | 1210 (1 row) -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'rankpart_1_prt_extra'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from gp_stat_all_tables_summary where relid = 'rankpart_1_prt_extra'::regclass; n_tup_ins | n_tup_upd | n_tup_del | n_tup_hot_upd | n_live_tup | n_dead_tup | n_mod_since_analyze -----------+-----------+-----------+---------------+------------+------------+--------------------- 300 | 0 | 10 | 0 | 300 | 0 | 300 @@ -492,13 +492,13 @@ insert into base_table select i,i,i from generate_series(1, 100) i; create materialized view mt as select * from base_table where z>=50; NOTICE: Table doesn't have 'DISTRIBUTED BY' clause -- Using column(s) named 'i' as the Apache Cloudberry data distribution key for this table. HINT: The 'DISTRIBUTED BY' clause determines the distribution of data. Make sure column(s) chosen are the optimal data distribution key to minimize skew. -select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. - pg_sleep ----------- +select gp_stat_force_next_flush(); + gp_stat_force_next_flush +-------------------------- (1 row) -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'mt'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from gp_stat_all_tables_summary where relid = 'mt'::regclass; n_tup_ins | n_tup_upd | n_tup_del | n_tup_hot_upd | n_live_tup | n_dead_tup | n_mod_since_analyze -----------+-----------+-----------+---------------+------------+------------+--------------------- 51 | 0 | 0 | 0 | 51 | 0 | 51 @@ -506,22 +506,20 @@ select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n insert into base_table select i,i,i from generate_series(1, 100) i; refresh materialized view mt; -select pg_sleep(0.77) from gp_dist_random('gp_id'); -- Force pgstat_report_stat() to send tabstat. - pg_sleep ----------- +select gp_stat_force_next_flush(); + gp_stat_force_next_flush +-------------------------- - - -(3 rows) +(1 row) -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'mt'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from gp_stat_all_tables_summary where relid = 'mt'::regclass; n_tup_ins | n_tup_upd | n_tup_del | n_tup_hot_upd | n_live_tup | n_dead_tup | n_mod_since_analyze -----------+-----------+-----------+---------------+------------+------------+--------------------- 153 | 0 | 0 | 0 | 102 | 0 | 153 (1 row) --- pg_stat_all_tables collects gpstats across segments -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables where relid = 'mt'::regclass; +-- gp_stat_all_tables_summary collects gpstats across segments +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from gp_stat_all_tables_summary where relid = 'mt'::regclass; n_tup_ins | n_tup_upd | n_tup_del | n_tup_hot_upd | n_live_tup | n_dead_tup | n_mod_since_analyze -----------+-----------+-----------+---------------+------------+------------+--------------------- 153 | 0 | 0 | 0 | 102 | 0 | 153 @@ -533,13 +531,13 @@ drop table base_table; create table base_table(i int, j int, z int ) distributed replicated; insert into base_table select i,i,i from generate_series(1, 100) i; create materialized view mt as select * from base_table where z>=50 distributed replicated; -select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. - pg_sleep ----------- +select gp_stat_force_next_flush(); + gp_stat_force_next_flush +-------------------------- (1 row) -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'mt'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from gp_stat_all_tables_summary where relid = 'mt'::regclass; n_tup_ins | n_tup_upd | n_tup_del | n_tup_hot_upd | n_live_tup | n_dead_tup | n_mod_since_analyze -----------+-----------+-----------+---------------+------------+------------+--------------------- 51 | 0 | 0 | 0 | 51 | 0 | 51 @@ -547,22 +545,20 @@ select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n insert into base_table select i,i,i from generate_series(1, 100) i; refresh materialized view mt; -select pg_sleep(0.77) from gp_dist_random('gp_id'); -- Force pgstat_report_stat() to send tabstat. - pg_sleep ----------- +select gp_stat_force_next_flush(); + gp_stat_force_next_flush +-------------------------- - - -(3 rows) +(1 row) -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'mt'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from gp_stat_all_tables_summary where relid = 'mt'::regclass; n_tup_ins | n_tup_upd | n_tup_del | n_tup_hot_upd | n_live_tup | n_dead_tup | n_mod_since_analyze -----------+-----------+-----------+---------------+------------+------------+--------------------- 153 | 0 | 0 | 0 | 102 | 0 | 153 (1 row) --- pg_stat_all_tables collects gpstats across segments -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables where relid = 'mt'::regclass; +-- gp_stat_all_tables_summary collects gpstats across segments +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from gp_stat_all_tables_summary where relid = 'mt'::regclass; n_tup_ins | n_tup_upd | n_tup_del | n_tup_hot_upd | n_live_tup | n_dead_tup | n_mod_since_analyze -----------+-----------+-----------+---------------+------------+------------+--------------------- 153 | 0 | 0 | 0 | 102 | 0 | 153 @@ -574,13 +570,13 @@ create table tabstat_ao(i int, j int) using ao_row distributed by (i); create index on tabstat_ao(i); insert into tabstat_ao select 1,1; delete from tabstat_ao; -select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. - pg_sleep ----------- +select gp_stat_force_next_flush(); + gp_stat_force_next_flush +-------------------------- (1 row) -select count(*) from pg_stat_all_tables +select count(*) from gp_stat_all_tables_summary where relid = (select segrelid from pg_appendonly where relid = 'tabstat_ao'::regclass) OR relid = (select blkdirrelid from pg_appendonly where relid = 'tabstat_ao'::regclass) @@ -590,25 +586,25 @@ where 3 (1 row) -select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. - pg_sleep ----------- +select gp_stat_force_next_flush(); + gp_stat_force_next_flush +-------------------------- (1 row) -select n_tup_ins from pg_stat_all_tables where relid = (select segrelid from pg_appendonly where relid = 'tabstat_ao'::regclass); +select n_tup_ins from gp_stat_all_tables_summary where relid = (select segrelid from pg_appendonly where relid = 'tabstat_ao'::regclass); n_tup_ins ----------- 1 (1 row) -select n_tup_ins from pg_stat_all_tables where relid = (select blkdirrelid from pg_appendonly where relid = 'tabstat_ao'::regclass); +select n_tup_ins from gp_stat_all_tables_summary where relid = (select blkdirrelid from pg_appendonly where relid = 'tabstat_ao'::regclass); n_tup_ins ----------- 1 (1 row) -select n_tup_ins from pg_stat_all_tables where relid = (select visimaprelid from pg_appendonly where relid = 'tabstat_ao'::regclass); +select n_tup_ins from gp_stat_all_tables_summary where relid = (select visimaprelid from pg_appendonly where relid = 'tabstat_ao'::regclass); n_tup_ins ----------- 1 diff --git a/src/test/regress/expected/runtime_stats.out b/src/test/regress/expected/runtime_stats.out index 0930f5cbfac..fbc32270f0d 100644 --- a/src/test/regress/expected/runtime_stats.out +++ b/src/test/regress/expected/runtime_stats.out @@ -7,13 +7,13 @@ create or replace function isSpilling(explain_query text) returns int as $$ rv = plpy.execute(explain_query) -search_text = 'Workfile: (' +search_text = 'Disk:' result = 0 for i in range(len(rv)): cur_line = rv[i]['QUERY PLAN'] if search_text.lower() in cur_line.lower(): - str_trim = cur_line.split('Workfile: (') - str_trim = str_trim[1].split(' spilling') + str_trim = cur_line.split('Disk: ') + str_trim = str_trim[1].split('kB') if int(str_trim[0]) > 0: result = 1 return result diff --git a/src/test/regress/expected/stats.out b/src/test/regress/expected/stats.out index 04ea7de5d16..33a65be5c47 100644 --- a/src/test/regress/expected/stats.out +++ b/src/test/regress/expected/stats.out @@ -26,11 +26,14 @@ SET LOCAL stats_fetch_consistency = snapshot; CREATE TABLE prevstats AS SELECT t.seq_scan, t.seq_tup_read, t.idx_scan, t.idx_tup_fetch, (b.heap_blks_read + b.heap_blks_hit) AS heap_blks, - (b.idx_blks_read + b.idx_blks_hit) AS idx_blks, - pg_stat_get_snapshot_timestamp() as snap_ts - FROM pg_catalog.pg_stat_user_tables AS t, + (b.idx_blks_read + b.idx_blks_hit) AS idx_blks + FROM pg_catalog.gp_stat_user_tables_summary AS t, pg_catalog.pg_statio_user_tables AS b WHERE t.relname='tenk2' AND b.relname='tenk2'; + -- start_ignore +SELECT seq_scan FROM gp_stat_user_tables_summary WHERE relname='tenk2'; +-- end_ignore +SELECT gp_stat_get_snapshot_timestamp() AS prv_snapshot_ts \gset COMMIT; -- test effects of TRUNCATE on n_live_tup/n_dead_tup counters CREATE TABLE trunc_stats_test(id serial); @@ -111,8 +114,8 @@ SELECT * FROM tenk2 where unique1 = 10; RESET enable_bitmapscan; -- ensure pending stats are flushed -SELECT pg_stat_force_next_flush(); - pg_stat_force_next_flush +SELECT gp_stat_force_next_flush(); + gp_stat_force_next_flush -------------------------- (1 row) @@ -121,7 +124,7 @@ SELECT pg_stat_force_next_flush(); BEGIN; SET LOCAL stats_fetch_consistency = snapshot; SELECT relname, n_tup_ins, n_tup_upd, n_tup_del, n_live_tup, n_dead_tup - FROM pg_stat_user_tables + FROM gp_stat_user_tables_summary WHERE relname like 'trunc_stats_test%' order by relname; relname | n_tup_ins | n_tup_upd | n_tup_del | n_live_tup | n_dead_tup -------------------+-----------+-----------+-----------+------------+------------ @@ -136,7 +139,7 @@ SELECT st.seq_scan >= pr.seq_scan + 1, st.seq_tup_read >= pr.seq_tup_read + cl.reltuples, st.idx_scan >= pr.idx_scan + 1, st.idx_tup_fetch >= pr.idx_tup_fetch + 1 - FROM pg_stat_user_tables AS st, pg_class AS cl, prevstats AS pr + FROM gp_stat_user_tables_summary AS st, pg_class AS cl, prevstats AS pr WHERE st.relname='tenk2' AND cl.relname='tenk2'; ?column? | ?column? | ?column? | ?column? ----------+----------+----------+---------- @@ -154,8 +157,7 @@ SELECT (SELECT sum(st.heap_blks_read) + sum(st.heap_blks_hit) - sum(pr.heap_blks t (1 row) -SELECT pr.snap_ts < pg_stat_get_snapshot_timestamp() as snapshot_newer -FROM prevstats AS pr; +SELECT :'prv_snapshot_ts' < pg_stat_get_snapshot_timestamp() as snapshot_newer; snapshot_newer ---------------- t @@ -254,8 +256,8 @@ SELECT stats_test_func2(); (1 row) ROLLBACK; -SELECT pg_stat_force_next_flush(); - pg_stat_force_next_flush +SELECT gp_stat_force_next_flush(); + gp_stat_force_next_flush -------------------------- (1 row) @@ -363,176 +365,170 @@ SELECT 'drop_stats_test_xact'::regclass::oid AS drop_stats_test_xact_oid \gset CREATE TABLE drop_stats_test_subxact(); INSERT INTO drop_stats_test_subxact DEFAULT VALUES; SELECT 'drop_stats_test_subxact'::regclass::oid AS drop_stats_test_subxact_oid \gset -SELECT pg_stat_force_next_flush(); - pg_stat_force_next_flush +SELECT gp_stat_force_next_flush(); + gp_stat_force_next_flush -------------------------- (1 row) -SELECT pg_stat_get_live_tuples(:drop_stats_test_oid); - pg_stat_get_live_tuples -------------------------- - 1 +SELECT n_live_tup FROM gp_stat_all_tables_summary WHERE relid = :drop_stats_test_oid; + n_live_tup +------------ + 1 (1 row) DROP TABLE drop_stats_test; -SELECT pg_stat_get_live_tuples(:drop_stats_test_oid); - pg_stat_get_live_tuples -------------------------- - 0 -(1 row) +SELECT n_live_tup FROM gp_stat_all_tables_summary WHERE relid = :drop_stats_test_oid; + n_live_tup +------------ +(0 rows) -SELECT pg_stat_get_xact_tuples_inserted(:drop_stats_test_oid); - pg_stat_get_xact_tuples_inserted ----------------------------------- - 0 -(1 row) +SELECT n_tup_ins FROM gp_stat_xact_all_tables_summary where relid = :drop_stats_test_oid; + n_tup_ins +----------- +(0 rows) -- check that rollback protects against having stats dropped and that local -- modifications don't pose a problem -SELECT pg_stat_get_live_tuples(:drop_stats_test_xact_oid); - pg_stat_get_live_tuples -------------------------- - 1 +SELECT n_live_tup FROM gp_stat_all_tables_summary WHERE relid = :drop_stats_test_xact_oid; + n_live_tup +------------ + 1 (1 row) -SELECT pg_stat_get_tuples_inserted(:drop_stats_test_xact_oid); - pg_stat_get_tuples_inserted ------------------------------ - 1 +SELECT n_tup_ins FROM gp_stat_all_tables_summary WHERE relid = :drop_stats_test_xact_oid; + n_tup_ins +----------- + 1 (1 row) -SELECT pg_stat_get_xact_tuples_inserted(:drop_stats_test_xact_oid); - pg_stat_get_xact_tuples_inserted ----------------------------------- - 0 +SELECT n_tup_ins FROM gp_stat_xact_all_tables_summary where relid = :drop_stats_test_xact_oid; + n_tup_ins +----------- + 0 (1 row) BEGIN; INSERT INTO drop_stats_test_xact DEFAULT VALUES; -SELECT pg_stat_get_xact_tuples_inserted(:drop_stats_test_xact_oid); - pg_stat_get_xact_tuples_inserted ----------------------------------- - 1 +SELECT n_tup_ins FROM gp_stat_xact_all_tables_summary where relid = :drop_stats_test_xact_oid; + n_tup_ins +----------- + 1 (1 row) DROP TABLE drop_stats_test_xact; -SELECT pg_stat_get_xact_tuples_inserted(:drop_stats_test_xact_oid); - pg_stat_get_xact_tuples_inserted ----------------------------------- - 0 -(1 row) +SELECT n_tup_ins FROM gp_stat_xact_all_tables_summary where relid = :drop_stats_test_xact_oid; + n_tup_ins +----------- +(0 rows) ROLLBACK; -SELECT pg_stat_force_next_flush(); - pg_stat_force_next_flush +SELECT gp_stat_force_next_flush(); + gp_stat_force_next_flush -------------------------- (1 row) -SELECT pg_stat_get_live_tuples(:drop_stats_test_xact_oid); - pg_stat_get_live_tuples -------------------------- - 1 +SELECT n_live_tup FROM gp_stat_all_tables_summary WHERE relid = :drop_stats_test_xact_oid; + n_live_tup +------------ + 1 (1 row) -SELECT pg_stat_get_tuples_inserted(:drop_stats_test_xact_oid); - pg_stat_get_tuples_inserted ------------------------------ - 2 +SELECT n_tup_ins FROM gp_stat_all_tables_summary WHERE relid = :drop_stats_test_xact_oid; + n_tup_ins +----------- + 2 (1 row) -- transactional drop -SELECT pg_stat_get_live_tuples(:drop_stats_test_xact_oid); - pg_stat_get_live_tuples -------------------------- - 1 +SELECT n_live_tup FROM gp_stat_all_tables_summary WHERE relid = :drop_stats_test_xact_oid; + n_live_tup +------------ + 1 (1 row) -SELECT pg_stat_get_tuples_inserted(:drop_stats_test_xact_oid); - pg_stat_get_tuples_inserted ------------------------------ - 2 +SELECT n_tup_ins FROM gp_stat_all_tables_summary WHERE relid = :drop_stats_test_xact_oid; + n_tup_ins +----------- + 2 (1 row) BEGIN; INSERT INTO drop_stats_test_xact DEFAULT VALUES; -SELECT pg_stat_get_xact_tuples_inserted(:drop_stats_test_xact_oid); - pg_stat_get_xact_tuples_inserted ----------------------------------- - 1 +SELECT n_tup_ins FROM gp_stat_xact_all_tables_summary where relid = :drop_stats_test_xact_oid; + n_tup_ins +----------- + 1 (1 row) DROP TABLE drop_stats_test_xact; -SELECT pg_stat_get_xact_tuples_inserted(:drop_stats_test_xact_oid); - pg_stat_get_xact_tuples_inserted ----------------------------------- - 0 -(1 row) +SELECT n_tup_ins FROM gp_stat_xact_all_tables_summary where relid = :drop_stats_test_xact_oid; + n_tup_ins +----------- +(0 rows) COMMIT; -SELECT pg_stat_force_next_flush(); - pg_stat_force_next_flush +SELECT gp_stat_force_next_flush(); + gp_stat_force_next_flush -------------------------- (1 row) -SELECT pg_stat_get_live_tuples(:drop_stats_test_xact_oid); - pg_stat_get_live_tuples -------------------------- - 0 -(1 row) +SELECT n_live_tup FROM gp_stat_all_tables_summary WHERE relid = :drop_stats_test_xact_oid; + n_live_tup +------------ +(0 rows) -SELECT pg_stat_get_tuples_inserted(:drop_stats_test_xact_oid); - pg_stat_get_tuples_inserted ------------------------------ - 0 -(1 row) +SELECT n_tup_ins FROM gp_stat_all_tables_summary WHERE relid = :drop_stats_test_xact_oid; + n_tup_ins +----------- +(0 rows) -- savepoint rollback (2 levels) -SELECT pg_stat_get_live_tuples(:drop_stats_test_subxact_oid); - pg_stat_get_live_tuples -------------------------- - 1 +SELECT n_live_tup FROM gp_stat_all_tables_summary WHERE relid = :drop_stats_test_subxact_oid; + n_live_tup +------------ + 1 (1 row) BEGIN; INSERT INTO drop_stats_test_subxact DEFAULT VALUES; SAVEPOINT sp1; INSERT INTO drop_stats_test_subxact DEFAULT VALUES; -SELECT pg_stat_get_xact_tuples_inserted(:drop_stats_test_subxact_oid); - pg_stat_get_xact_tuples_inserted ----------------------------------- - 2 +SELECT n_tup_ins FROM gp_stat_xact_all_tables_summary where relid = :drop_stats_test_subxact_oid; + n_tup_ins +----------- + 2 (1 row) SAVEPOINT sp2; DROP TABLE drop_stats_test_subxact; ROLLBACK TO SAVEPOINT sp2; -SELECT pg_stat_get_xact_tuples_inserted(:drop_stats_test_subxact_oid); - pg_stat_get_xact_tuples_inserted ----------------------------------- - 2 +SELECT n_tup_ins FROM gp_stat_xact_all_tables_summary where relid = :drop_stats_test_subxact_oid; + n_tup_ins +----------- + 2 (1 row) COMMIT; -SELECT pg_stat_force_next_flush(); - pg_stat_force_next_flush +SELECT gp_stat_force_next_flush(); + gp_stat_force_next_flush -------------------------- (1 row) -SELECT pg_stat_get_live_tuples(:drop_stats_test_subxact_oid); - pg_stat_get_live_tuples -------------------------- - 3 +SELECT n_live_tup FROM gp_stat_all_tables_summary WHERE relid = :drop_stats_test_subxact_oid; + n_live_tup +------------ + 3 (1 row) -- savepoint rolback (1 level) -SELECT pg_stat_get_live_tuples(:drop_stats_test_subxact_oid); - pg_stat_get_live_tuples -------------------------- - 3 +SELECT n_live_tup FROM gp_stat_all_tables_summary WHERE relid = :drop_stats_test_subxact_oid; + n_live_tup +------------ + 3 (1 row) BEGIN; @@ -541,17 +537,17 @@ DROP TABLE drop_stats_test_subxact; SAVEPOINT sp2; ROLLBACK TO SAVEPOINT sp1; COMMIT; -SELECT pg_stat_get_live_tuples(:drop_stats_test_subxact_oid); - pg_stat_get_live_tuples -------------------------- - 3 +SELECT n_live_tup FROM gp_stat_all_tables_summary WHERE relid = :drop_stats_test_subxact_oid; + n_live_tup +------------ + 3 (1 row) -- and now actually drop -SELECT pg_stat_get_live_tuples(:drop_stats_test_subxact_oid); - pg_stat_get_live_tuples -------------------------- - 3 +SELECT n_live_tup FROM gp_stat_all_tables_summary WHERE relid = :drop_stats_test_subxact_oid; + n_live_tup +------------ + 3 (1 row) BEGIN; @@ -560,11 +556,10 @@ DROP TABLE drop_stats_test_subxact; SAVEPOINT sp2; RELEASE SAVEPOINT sp1; COMMIT; -SELECT pg_stat_get_live_tuples(:drop_stats_test_subxact_oid); - pg_stat_get_live_tuples -------------------------- - 0 -(1 row) +SELECT n_live_tup FROM gp_stat_all_tables_summary WHERE relid = :drop_stats_test_subxact_oid; + n_live_tup +------------ +(0 rows) DROP TABLE trunc_stats_test, trunc_stats_test1, trunc_stats_test2, trunc_stats_test3, trunc_stats_test4; DROP TABLE prevstats; @@ -579,26 +574,26 @@ DROP TABLE prevstats; BEGIN; CREATE TEMPORARY TABLE test_last_scan(idx_col int primary key, noidx_col int); INSERT INTO test_last_scan(idx_col, noidx_col) VALUES(1, 1); -SELECT pg_stat_force_next_flush(); - pg_stat_force_next_flush +SELECT gp_stat_force_next_flush(); + gp_stat_force_next_flush -------------------------- (1 row) -SELECT last_seq_scan, last_idx_scan FROM pg_stat_all_tables WHERE relid = 'test_last_scan'::regclass; +SELECT last_seq_scan, last_idx_scan FROM gp_stat_all_tables_summary WHERE relid = 'test_last_scan'::regclass; last_seq_scan | last_idx_scan ---------------+--------------- | (1 row) COMMIT; -SELECT pg_stat_reset_single_table_counters('test_last_scan'::regclass); - pg_stat_reset_single_table_counters +SELECT gp_stat_reset_single_table_counters('test_last_scan'::regclass); + gp_stat_reset_single_table_counters ------------------------------------- (1 row) -SELECT seq_scan, idx_scan FROM pg_stat_all_tables WHERE relid = 'test_last_scan'::regclass; +SELECT seq_scan, idx_scan FROM gp_stat_all_tables_summary WHERE relid = 'test_last_scan'::regclass; seq_scan | idx_scan ----------+---------- 0 | 0 @@ -643,8 +638,8 @@ SELECT count(*) FROM test_last_scan WHERE idx_col = 1; 1 (1 row) -SELECT pg_stat_force_next_flush(); - pg_stat_force_next_flush +SELECT gp_stat_force_next_flush(); + gp_stat_force_next_flush -------------------------- (1 row) @@ -652,7 +647,7 @@ SELECT pg_stat_force_next_flush(); COMMIT; -- fetch timestamps from before the next test SELECT last_seq_scan AS test_last_seq, last_idx_scan AS test_last_idx -FROM pg_stat_all_tables WHERE relid = 'test_last_scan'::regclass \gset +FROM gp_stat_all_tables_summary WHERE relid = 'test_last_scan'::regclass \gset SELECT pg_sleep(0.1); -- assume a minimum timestamp granularity of 100ms pg_sleep ---------- @@ -681,8 +676,8 @@ SELECT count(*) FROM test_last_scan WHERE noidx_col = 1; 1 (1 row) -SELECT pg_stat_force_next_flush(); - pg_stat_force_next_flush +SELECT gp_stat_force_next_flush(); + gp_stat_force_next_flush -------------------------- (1 row) @@ -690,15 +685,15 @@ SELECT pg_stat_force_next_flush(); COMMIT; -- check that just sequential scan stats were incremented SELECT seq_scan, :'test_last_seq' < last_seq_scan AS seq_ok, idx_scan, :'test_last_idx' = last_idx_scan AS idx_ok -FROM pg_stat_all_tables WHERE relid = 'test_last_scan'::regclass; +FROM gp_stat_all_tables_summary WHERE relid = 'test_last_scan'::regclass; seq_scan | seq_ok | idx_scan | idx_ok ----------+--------+----------+-------- - 2 | t | 1 | t + 6 | t | 1 | t (1 row) -- fetch timestamps from before the next test SELECT last_seq_scan AS test_last_seq, last_idx_scan AS test_last_idx -FROM pg_stat_all_tables WHERE relid = 'test_last_scan'::regclass \gset +FROM gp_stat_all_tables_summary WHERE relid = 'test_last_scan'::regclass \gset SELECT pg_sleep(0.1); pg_sleep ---------- @@ -726,8 +721,8 @@ SELECT count(*) FROM test_last_scan WHERE idx_col = 1; 1 (1 row) -SELECT pg_stat_force_next_flush(); - pg_stat_force_next_flush +SELECT gp_stat_force_next_flush(); + gp_stat_force_next_flush -------------------------- (1 row) @@ -735,15 +730,15 @@ SELECT pg_stat_force_next_flush(); COMMIT; -- check that just index scan stats were incremented SELECT seq_scan, :'test_last_seq' = last_seq_scan AS seq_ok, idx_scan, :'test_last_idx' < last_idx_scan AS idx_ok -FROM pg_stat_all_tables WHERE relid = 'test_last_scan'::regclass; +FROM gp_stat_all_tables_summary WHERE relid = 'test_last_scan'::regclass; seq_scan | seq_ok | idx_scan | idx_ok ----------+--------+----------+-------- - 2 | t | 2 | t + 6 | t | 2 | t (1 row) -- fetch timestamps from before the next test SELECT last_seq_scan AS test_last_seq, last_idx_scan AS test_last_idx -FROM pg_stat_all_tables WHERE relid = 'test_last_scan'::regclass \gset +FROM gp_stat_all_tables_summary WHERE relid = 'test_last_scan'::regclass \gset SELECT pg_sleep(0.1); pg_sleep ---------- @@ -773,8 +768,8 @@ SELECT count(*) FROM test_last_scan WHERE idx_col = 1; 1 (1 row) -SELECT pg_stat_force_next_flush(); - pg_stat_force_next_flush +SELECT gp_stat_force_next_flush(); + gp_stat_force_next_flush -------------------------- (1 row) @@ -782,10 +777,10 @@ SELECT pg_stat_force_next_flush(); COMMIT; -- check that just index scan stats were incremented SELECT seq_scan, :'test_last_seq' = last_seq_scan AS seq_ok, idx_scan, :'test_last_idx' < last_idx_scan AS idx_ok -FROM pg_stat_all_tables WHERE relid = 'test_last_scan'::regclass; +FROM gp_stat_all_tables_summary WHERE relid = 'test_last_scan'::regclass; seq_scan | seq_ok | idx_scan | idx_ok ----------+--------+----------+-------- - 2 | t | 3 | t + 6 | t | 3 | t (1 row) ----- @@ -800,28 +795,28 @@ SELECT shobj_description(d.oid, 'pg_database') as description_before BEGIN; SELECT current_database() as datname \gset COMMENT ON DATABASE :"datname" IS 'This is a test comment'; -SELECT pg_stat_force_next_flush(); - pg_stat_force_next_flush +SELECT gp_stat_force_next_flush(); + gp_stat_force_next_flush -------------------------- (1 row) COMMIT; -- check that the stats are reset. -SELECT (n_tup_ins + n_tup_upd) > 0 AS has_data FROM pg_stat_all_tables +SELECT (n_tup_ins + n_tup_upd) > 0 AS has_data FROM gp_stat_all_tables_summary WHERE relid = 'pg_shdescription'::regclass; has_data ---------- t (1 row) -SELECT pg_stat_reset_single_table_counters('pg_shdescription'::regclass); - pg_stat_reset_single_table_counters +SELECT gp_stat_reset_single_table_counters('pg_shdescription'::regclass); + gp_stat_reset_single_table_counters ------------------------------------- (1 row) -SELECT (n_tup_ins + n_tup_upd) > 0 AS has_data FROM pg_stat_all_tables +SELECT (n_tup_ins + n_tup_upd) > 0 AS has_data FROM gp_stat_all_tables_summary WHERE relid = 'pg_shdescription'::regclass; has_data ---------- @@ -840,8 +835,8 @@ SELECT (n_tup_ins + n_tup_upd) > 0 AS has_data FROM pg_stat_all_tables -- 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 pg_stat_force_next_flush(); - pg_stat_force_next_flush +SELECT gp_stat_force_next_flush(); + gp_stat_force_next_flush -------------------------- (1 row) @@ -878,14 +873,10 @@ SELECT wal_bytes > :wal_bytes_before FROM pg_stat_wal; -- Test pg_stat_get_backend_idset() and some allied functions. -- In particular, verify that their notion of backend ID matches -- our temp schema index. -SELECT (current_schemas(true))[1] = ('pg_temp_' || beid::text) AS match -FROM pg_stat_get_backend_idset() beid -WHERE pg_stat_get_backend_pid(beid) = pg_backend_pid(); - match -------- - t -(1 row) - +-- In CBDB temp schema use ('pg_temp_' || gp_session_id::text) +-- SELECT (current_schemas(true))[1] = ('pg_temp_' || beid::text) AS match +-- FROM pg_stat_get_backend_idset() beid +-- WHERE pg_stat_get_backend_pid(beid) = pg_backend_pid(); ----- -- Test that resetting stats works for reset timestamp ----- @@ -926,8 +917,8 @@ SELECT stats_reset > :'slru_notify_reset_ts'::timestamptz FROM pg_stat_slru WHER -- 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 +SELECT gp_stat_reset_shared('archiver'); + gp_stat_reset_shared ---------------------- (1 row) @@ -941,8 +932,8 @@ 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'); - pg_stat_reset_shared +SELECT gp_stat_reset_shared('bgwriter'); + gp_stat_reset_shared ---------------------- (1 row) @@ -956,8 +947,8 @@ 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'); - pg_stat_reset_shared +SELECT gp_stat_reset_shared('wal'); + gp_stat_reset_shared ---------------------- (1 row) @@ -970,8 +961,8 @@ 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); - pg_stat_reset_shared +SELECT gp_stat_reset_shared(NULL); + gp_stat_reset_shared ---------------------- (1 row) @@ -1255,7 +1246,7 @@ SELECT pg_stat_get_subscription_stats(NULL); (1 row) --- Test that the following operations are tracked in pg_stat_io: +-- Test that the following operations are tracked in gp_stat_io_summary: -- - reads of target blocks into shared buffers -- - writes of shared buffers to permanent storage -- - extends of relations using shared buffers @@ -1266,20 +1257,20 @@ SELECT pg_stat_get_subscription_stats(NULL); -- Create a regular table and insert some data to generate IOCONTEXT_NORMAL -- extends. SELECT sum(extends) AS io_sum_shared_before_extends - FROM pg_stat_io WHERE context = 'normal' AND object = 'relation' \gset + FROM gp_stat_io_summary WHERE context = 'normal' AND object = 'relation' \gset SELECT sum(writes) AS writes, sum(fsyncs) AS fsyncs - FROM pg_stat_io + FROM gp_stat_io_summary WHERE object = 'relation' \gset io_sum_shared_before_ CREATE TABLE test_io_shared(a int); INSERT INTO test_io_shared SELECT i FROM generate_series(1,100)i; -SELECT pg_stat_force_next_flush(); - pg_stat_force_next_flush +SELECT gp_stat_force_next_flush(); + gp_stat_force_next_flush -------------------------- (1 row) SELECT sum(extends) AS io_sum_shared_after_extends - FROM pg_stat_io WHERE context = 'normal' AND object = 'relation' \gset + FROM gp_stat_io_summary WHERE context = 'normal' AND object = 'relation' \gset SELECT :io_sum_shared_after_extends > :io_sum_shared_before_extends; ?column? ---------- @@ -1292,7 +1283,7 @@ SELECT :io_sum_shared_after_extends > :io_sum_shared_before_extends; CHECKPOINT; CHECKPOINT; SELECT sum(writes) AS writes, sum(fsyncs) AS fsyncs - FROM pg_stat_io + FROM gp_stat_io_summary WHERE object = 'relation' \gset io_sum_shared_after_ SELECT :io_sum_shared_after_writes > :io_sum_shared_before_writes; ?column? @@ -1310,7 +1301,7 @@ SELECT current_setting('fsync') = 'off' -- Change the tablespace so that the table is rewritten directly, then SELECT -- from it to cause it to be read back into shared buffers. SELECT sum(reads) AS io_sum_shared_before_reads - FROM pg_stat_io WHERE context = 'normal' AND object = 'relation' \gset + FROM gp_stat_io_summary WHERE context = 'normal' AND object = 'relation' \gset -- Do this in a transaction to prevent spurious failures due to concurrent accesses to our newly -- rewritten table, e.g. by autovacuum. BEGIN; @@ -1324,14 +1315,14 @@ SELECT COUNT(*) FROM test_io_shared; (1 row) COMMIT; -SELECT pg_stat_force_next_flush(); - pg_stat_force_next_flush +SELECT gp_stat_force_next_flush(); + gp_stat_force_next_flush -------------------------- (1 row) SELECT sum(reads) AS io_sum_shared_after_reads - FROM pg_stat_io WHERE context = 'normal' AND object = 'relation' \gset + FROM gp_stat_io_summary WHERE context = 'normal' AND object = 'relation' \gset SELECT :io_sum_shared_after_reads > :io_sum_shared_before_reads; ?column? ---------- @@ -1339,7 +1330,7 @@ SELECT :io_sum_shared_after_reads > :io_sum_shared_before_reads; (1 row) SELECT sum(hits) AS io_sum_shared_before_hits - FROM pg_stat_io WHERE context = 'normal' AND object = 'relation' \gset + FROM gp_stat_io_summary WHERE context = 'normal' AND object = 'relation' \gset -- Select from the table again to count hits. -- Ensure we generate hits by forcing a nested loop self-join with no -- materialize node. The outer side's buffer will stay pinned, preventing its @@ -1368,14 +1359,14 @@ SELECT COUNT(*) FROM test_io_shared t1 INNER JOIN test_io_shared t2 USING (a); (1 row) COMMIT; -SELECT pg_stat_force_next_flush(); - pg_stat_force_next_flush +SELECT gp_stat_force_next_flush(); + gp_stat_force_next_flush -------------------------- (1 row) SELECT sum(hits) AS io_sum_shared_after_hits - FROM pg_stat_io WHERE context = 'normal' AND object = 'relation' \gset + FROM gp_stat_io_summary WHERE context = 'normal' AND object = 'relation' \gset SELECT :io_sum_shared_after_hits > :io_sum_shared_before_hits; ?column? ---------- @@ -1383,7 +1374,7 @@ SELECT :io_sum_shared_after_hits > :io_sum_shared_before_hits; (1 row) DROP TABLE test_io_shared; --- Test that the follow IOCONTEXT_LOCAL IOOps are tracked in pg_stat_io: +-- Test that the follow IOCONTEXT_LOCAL IOOps are tracked in gp_stat_io_summary: -- - eviction of local buffers in order to reuse them -- - reads of temporary table blocks into local buffers -- - writes of local buffers to permanent storage @@ -1391,16 +1382,18 @@ DROP TABLE test_io_shared; -- Set temp_buffers to its minimum so that we can trigger writes with fewer -- inserted tuples. Do so in a new session in case temporary tables have been -- accessed by previous tests in this session. +-- CBDB: CBDB use share buffer not local buffer.So extends with object = 'relation' not 'temp relation'. +-- read/write will not count directly, result is false \c SET temp_buffers TO 100; CREATE TEMPORARY TABLE test_io_local(a int, b TEXT); SELECT sum(extends) AS extends, sum(evictions) AS evictions, sum(writes) AS writes FROM pg_stat_io - WHERE context = 'normal' AND object = 'temp relation' \gset io_sum_local_before_ + WHERE context = 'normal' AND object = 'relation' \gset io_sum_local_before_ -- Insert tuples into the temporary table, generating extends in the stats. -- Insert enough values that we need to reuse and write out dirty local -- buffers, generating evictions and writes. -INSERT INTO test_io_local SELECT generate_series(1, 5000) as id, repeat('a', 200); +INSERT INTO test_io_local SELECT generate_series(1, 50000) as id, repeat('a', 800); -- Ensure the table is large enough to exceed our temp_buffers setting. SELECT pg_relation_size('test_io_local') / current_setting('block_size')::int8 > 100; ?column? @@ -1409,16 +1402,16 @@ SELECT pg_relation_size('test_io_local') / current_setting('block_size')::int8 > (1 row) SELECT sum(reads) AS io_sum_local_before_reads - FROM pg_stat_io WHERE context = 'normal' AND object = 'temp relation' \gset + FROM gp_stat_io_summary WHERE context = 'normal' AND object = 'relation' \gset -- Read in evicted buffers, generating reads. SELECT COUNT(*) FROM test_io_local; count ------- - 5000 + 50000 (1 row) -SELECT pg_stat_force_next_flush(); - pg_stat_force_next_flush +SELECT gp_stat_force_next_flush(); + gp_stat_force_next_flush -------------------------- (1 row) @@ -1427,29 +1420,29 @@ SELECT sum(evictions) AS evictions, sum(reads) AS reads, sum(writes) AS writes, sum(extends) AS extends - FROM pg_stat_io - WHERE context = 'normal' AND object = 'temp relation' \gset io_sum_local_after_ + FROM gp_stat_io_summary + WHERE context = 'normal' AND object = 'relation' \gset io_sum_local_after_ SELECT :io_sum_local_after_evictions > :io_sum_local_before_evictions, :io_sum_local_after_reads > :io_sum_local_before_reads, :io_sum_local_after_writes > :io_sum_local_before_writes, :io_sum_local_after_extends > :io_sum_local_before_extends; ?column? | ?column? | ?column? | ?column? ----------+----------+----------+---------- - t | t | t | t + f | f | t | t (1 row) -- Change the tablespaces so that the temporary table is rewritten to other -- local buffers, exercising a different codepath than standard local buffer -- writes. ALTER TABLE test_io_local SET TABLESPACE regress_tblspace; -SELECT pg_stat_force_next_flush(); - pg_stat_force_next_flush +SELECT gp_stat_force_next_flush(); + gp_stat_force_next_flush -------------------------- (1 row) SELECT sum(writes) AS io_sum_local_new_tblspc_writes - FROM pg_stat_io WHERE context = 'normal' AND object = 'temp relation' \gset + FROM gp_stat_io_summary WHERE context = 'normal' AND object = 'relation' \gset SELECT :io_sum_local_new_tblspc_writes > :io_sum_local_after_writes; ?column? ---------- @@ -1458,7 +1451,7 @@ SELECT :io_sum_local_new_tblspc_writes > :io_sum_local_after_writes; RESET temp_buffers; -- Test that reuse of strategy buffers and reads of blocks into these reused --- buffers while VACUUMing are tracked in pg_stat_io. If there is sufficient +-- buffers while VACUUMing are tracked in gp_stat_io_summary. If there is sufficient -- demand for shared buffers from concurrent queries, some buffers may be -- pinned by other backends before they can be reused. In such cases, the -- backend will evict a buffer from outside the ring and add it to the @@ -1471,23 +1464,23 @@ RESET temp_buffers; -- reads. SET wal_skip_threshold = '1 kB'; SELECT sum(reuses) AS reuses, sum(reads) AS reads, sum(evictions) AS evictions - FROM pg_stat_io WHERE context = 'vacuum' \gset io_sum_vac_strategy_before_ + FROM gp_stat_io_summary WHERE context = 'vacuum' \gset io_sum_vac_strategy_before_ CREATE TABLE test_io_vac_strategy(a int, b int) WITH (autovacuum_enabled = 'false'); -INSERT INTO test_io_vac_strategy SELECT i, i from generate_series(1, 4500)i; +INSERT INTO test_io_vac_strategy SELECT i, i from generate_series(1, 45000)i; -- Ensure that the next VACUUM will need to perform IO by rewriting the table -- first with VACUUM (FULL). VACUUM (FULL) test_io_vac_strategy; -- Use the minimum BUFFER_USAGE_LIMIT to cause reuses or evictions with the -- smallest table possible. VACUUM (PARALLEL 0, BUFFER_USAGE_LIMIT 128) test_io_vac_strategy; -SELECT pg_stat_force_next_flush(); - pg_stat_force_next_flush +SELECT gp_stat_force_next_flush(); + gp_stat_force_next_flush -------------------------- (1 row) SELECT sum(reuses) AS reuses, sum(reads) AS reads, sum(evictions) AS evictions - FROM pg_stat_io WHERE context = 'vacuum' \gset io_sum_vac_strategy_after_ + FROM gp_stat_io_summary WHERE context = 'vacuum' \gset io_sum_vac_strategy_after_ SELECT :io_sum_vac_strategy_after_reads > :io_sum_vac_strategy_before_reads; ?column? ---------- @@ -1503,18 +1496,18 @@ SELECT (:io_sum_vac_strategy_after_reuses + :io_sum_vac_strategy_after_evictions RESET wal_skip_threshold; -- Test that extends done by a CTAS, which uses a BAS_BULKWRITE --- BufferAccessStrategy, are tracked in pg_stat_io. +-- BufferAccessStrategy, are tracked in gp_stat_io_summary. SELECT sum(extends) AS io_sum_bulkwrite_strategy_extends_before - FROM pg_stat_io WHERE context = 'bulkwrite' \gset + FROM gp_stat_io_summary WHERE context = 'bulkwrite' \gset CREATE TABLE test_io_bulkwrite_strategy AS SELECT i FROM generate_series(1,100)i; -SELECT pg_stat_force_next_flush(); - pg_stat_force_next_flush +SELECT gp_stat_force_next_flush(); + gp_stat_force_next_flush -------------------------- (1 row) SELECT sum(extends) AS io_sum_bulkwrite_strategy_extends_after - FROM pg_stat_io WHERE context = 'bulkwrite' \gset + FROM gp_stat_io_summary WHERE context = 'bulkwrite' \gset SELECT :io_sum_bulkwrite_strategy_extends_after > :io_sum_bulkwrite_strategy_extends_before; ?column? ---------- @@ -1529,15 +1522,15 @@ SELECT pg_stat_have_stats('io', 0, 0); (1 row) SELECT sum(evictions) + sum(reuses) + sum(extends) + sum(fsyncs) + sum(reads) + sum(writes) + sum(writebacks) + sum(hits) AS io_stats_pre_reset - FROM pg_stat_io \gset -SELECT pg_stat_reset_shared('io'); - pg_stat_reset_shared + FROM gp_stat_io_summary \gset +SELECT gp_stat_reset_shared('io'); + gp_stat_reset_shared ---------------------- (1 row) SELECT sum(evictions) + sum(reuses) + sum(extends) + sum(fsyncs) + sum(reads) + sum(writes) + sum(writebacks) + sum(hits) AS io_stats_post_reset - FROM pg_stat_io \gset + FROM gp_stat_io_summary \gset SELECT :io_stats_post_reset < :io_stats_pre_reset; ?column? ---------- @@ -1558,7 +1551,7 @@ DECLARE BEGIN -- we don't want to wait forever; loop will exit after 30 seconds FOR i IN 1 .. 300 LOOP - SELECT (pg_stat_get_tuples_hot_updated('brin_hot'::regclass::oid) > 0) INTO updated; + SELECT n_tup_upd > 0 INTO updated FROM gp_stat_user_tables_summary WHERE relid = ('brin_hot'::regclass::oid); EXIT WHEN updated; -- wait a little @@ -1585,10 +1578,10 @@ SELECT wait_for_hot_stats(); (1 row) -SELECT pg_stat_get_tuples_hot_updated('brin_hot'::regclass::oid); - pg_stat_get_tuples_hot_updated --------------------------------- - 1 +select n_tup_upd from gp_stat_user_tables_summary where relid = ('brin_hot'::regclass::oid); + n_tup_upd +----------- + 1 (1 row) DROP TABLE brin_hot; diff --git a/src/test/regress/sql/pg_stat.sql b/src/test/regress/sql/pg_stat.sql index d9fc37850b0..f2d3c72bf70 100644 --- a/src/test/regress/sql/pg_stat.sql +++ b/src/test/regress/sql/pg_stat.sql @@ -6,17 +6,17 @@ create table pg_stat_test(a int); select schemaname, relname, seq_scan, seq_tup_read, idx_scan, idx_tup_fetch, n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup -from pg_stat_all_tables where relname = 'pg_stat_test'; +from gp_stat_all_tables_summary where relname = 'pg_stat_test'; select schemaname, relname, seq_scan, seq_tup_read, idx_scan, idx_tup_fetch, n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup -from pg_stat_user_tables where relname = 'pg_stat_test'; +from gp_stat_user_tables_summary where relname = 'pg_stat_test'; select schemaname, relname, indexrelname, idx_scan, idx_tup_read, idx_tup_fetch -from pg_stat_all_indexes where relname = 'pg_stat_test'; +from gp_stat_all_indexes_summary where relname = 'pg_stat_test'; select schemaname, relname, indexrelname, idx_scan, idx_tup_read, idx_tup_fetch -from pg_stat_user_indexes where relname = 'pg_stat_test'; +from gp_stat_user_indexes_summary where relname = 'pg_stat_test'; begin; -- make analyze same transcation with insert to avoid double the pgstat causes by unorder message read. insert into pg_stat_test select * from generate_series(1, 100); @@ -39,20 +39,22 @@ select * from pg_stat_test where a = 1; reset enable_seqscan; +select gp_stat_force_next_flush(); + select schemaname, relname, seq_scan, seq_tup_read, idx_scan, idx_tup_fetch, n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze -from pg_stat_all_tables where relname = 'pg_stat_test'; +from gp_stat_all_tables_summary where relname = 'pg_stat_test'; select schemaname, relname, seq_scan, seq_tup_read, idx_scan, idx_tup_fetch, n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze -from pg_stat_user_tables where relname = 'pg_stat_test'; +from gp_stat_user_tables_summary where relname = 'pg_stat_test'; select schemaname, relname, indexrelname, idx_scan, idx_tup_read, idx_tup_fetch -from pg_stat_all_indexes where relname = 'pg_stat_test'; +from gp_stat_all_indexes_summary where relname = 'pg_stat_test'; select schemaname, relname, indexrelname, idx_scan, idx_tup_read, idx_tup_fetch -from pg_stat_user_indexes where relname = 'pg_stat_test'; +from gp_stat_user_indexes_summary where relname = 'pg_stat_test'; reset optimizer; reset max_parallel_workers_per_gather; diff --git a/src/test/regress/sql/pgstat_qd_tabstat.sql b/src/test/regress/sql/pgstat_qd_tabstat.sql index 0fb8c0ccb71..b93d9def221 100644 --- a/src/test/regress/sql/pgstat_qd_tabstat.sql +++ b/src/test/regress/sql/pgstat_qd_tabstat.sql @@ -9,8 +9,8 @@ copy table_for_docopy (i, j) from stdin; 1 hello1 3 hello3 \. -select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'table_for_docopy'::regclass; +select gp_stat_force_next_flush(); +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from gp_stat_all_tables_summary where relid = 'table_for_docopy'::regclass; CREATE TABLE data_tbl (a int,b char) distributed by (a); INSERT INTO data_tbl values(1,'1'); @@ -20,8 +20,8 @@ INSERT INTO data_tbl values(1,'b'); COPY data_tbl TO '/tmp/data_tbl.csv' on segment; create table copy_on_segment (a int,b char); COPY copy_on_segment from '/tmp/data_tbl.csv' on segment log errors segment reject limit 3 rows; -select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'copy_on_segment'::regclass; +select gp_stat_force_next_flush(); +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from gp_stat_all_tables_summary where relid = 'copy_on_segment'::regclass; -- Test pgstat table stat in initplan on QD @@ -33,27 +33,27 @@ copy table_for_initplan (i, j, k) from stdin; \. explain (costs off) with updated AS (update table_for_initplan set k = 33 where i = 3 returning k) select table_for_initplan.*, (select sum(k) from updated) from table_for_initplan; with updated AS (update table_for_initplan set k = 33 where i = 3 returning k) select table_for_initplan.*, (select sum(k) from updated) from table_for_initplan; -select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'table_for_initplan'::regclass; +select gp_stat_force_next_flush(); +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from gp_stat_all_tables_summary where relid = 'table_for_initplan'::regclass; -- Test pgstat table stat in CTAS on QD create table table_for_ctas with (autovacuum_enabled=false) as select i, 'hello' || i from generate_series(1, 100) f(i); -select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'table_for_ctas'::regclass; +select gp_stat_force_next_flush(); +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from gp_stat_all_tables_summary where relid = 'table_for_ctas'::regclass; select i, 'hello' || i into table_for_insert_into from generate_series(1, 100) f(i); -select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'table_for_insert_into'::regclass; +select gp_stat_force_next_flush(); +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from gp_stat_all_tables_summary where relid = 'table_for_insert_into'::regclass; -- Test pgstat table stat in ALTER TABLE SET DISTRIBUTED BY on QD create table table_for_set_distributed_by(i int, j varchar) distributed by (i); insert into table_for_set_distributed_by select i, 'hello' || i from generate_series(1, 333) f(i); -select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'table_for_set_distributed_by'::regclass; +select gp_stat_force_next_flush(); +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from gp_stat_all_tables_summary where relid = 'table_for_set_distributed_by'::regclass; alter table table_for_set_distributed_by set distributed by (j); -select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'table_for_set_distributed_by'::regclass; +select gp_stat_force_next_flush(); +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from gp_stat_all_tables_summary where relid = 'table_for_set_distributed_by'::regclass; -- Test pgstat table stat in execution of funciton on QD @@ -67,8 +67,8 @@ $$ $$ language plpgsql volatile; select update_table_for_function(); -select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'table_for_function'::regclass; +select gp_stat_force_next_flush(); +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from gp_stat_all_tables_summary where relid = 'table_for_function'::regclass; -- Test pgstat table stat in ALTER TABLE EXPAND TABLE on QD; @@ -77,12 +77,12 @@ select gp_debug_set_create_table_default_numsegments(1); create table table_for_expand(i int, j varchar) distributed by (i); insert into table_for_expand select i, 'hello' || i from generate_series(1, 333) f(i); select count(distinct gp_segment_id) from table_for_expand; -select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'table_for_expand'::regclass; +select gp_stat_force_next_flush(); +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from gp_stat_all_tables_summary where relid = 'table_for_expand'::regclass; alter table table_for_expand expand table; select count(distinct gp_segment_id) from table_for_expand; -select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'table_for_expand'::regclass; +select gp_stat_force_next_flush(); +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from gp_stat_all_tables_summary where relid = 'table_for_expand'::regclass; select gp_debug_reset_create_table_default_numsegments(); @@ -102,8 +102,8 @@ rollback to savepoint level5; update table_for_iud set j = 'heroes never die' where i >= 300; release savepoint level3; commit; -select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. -select n_live_tup, n_dead_tup from pg_stat_all_tables_internal where relid = 'table_for_iud'::regclass; +select gp_stat_force_next_flush(); +select n_live_tup, n_dead_tup from gp_stat_all_tables_summary where relid = 'table_for_iud'::regclass; begin; savepoint level1; @@ -119,15 +119,15 @@ update table_for_iud set j = 'are you ok' where i >= 300; rollback to savepoint level3; delete from table_for_iud where i <= 200; commit; -select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. -select n_live_tup, n_dead_tup from pg_stat_all_tables_internal where relid = 'table_for_iud'::regclass; +select gp_stat_force_next_flush(); +select n_live_tup, n_dead_tup from gp_stat_all_tables_summary where relid = 'table_for_iud'::regclass; -- Test pgstat table stat in TRUNCATE on QD create table table_for_truncate(i int, j varchar) distributed by (i); insert into table_for_truncate select i, 'hello' || i from generate_series(1, 777) f(i); -select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'table_for_truncate'::regclass; +select gp_stat_force_next_flush(); +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from gp_stat_all_tables_summary where relid = 'table_for_truncate'::regclass; begin; savepoint level1; savepoint level2; @@ -140,13 +140,13 @@ insert into table_for_truncate select i, 'hello' || i from generate_series(1, 80 delete from table_for_truncate where i >= 700; update table_for_truncate set j = 'D' where i <= 200; commit; -select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. -select n_live_tup, n_dead_tup from pg_stat_all_tables_internal where relid = 'table_for_truncate'::regclass; +select gp_stat_force_next_flush(); +select n_live_tup, n_dead_tup from gp_stat_all_tables_summary where relid = 'table_for_truncate'::regclass; create table table_for_truncate_abort(i int, j varchar) distributed by (i); insert into table_for_truncate_abort select i, 'hello' || i from generate_series(1, 777) f(i); -select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. -select n_live_tup, n_dead_tup from pg_stat_all_tables_internal where relid = 'table_for_truncate_abort'::regclass; +select gp_stat_force_next_flush(); +select n_live_tup, n_dead_tup from gp_stat_all_tables_summary where relid = 'table_for_truncate_abort'::regclass; begin; savepoint level1; savepoint level2; @@ -159,8 +159,8 @@ insert into table_for_truncate_abort select i, 'hello' || i from generate_series delete from table_for_truncate_abort where i < 700; update table_for_truncate_abort set j = 'D' where i >= 200; rollback; -select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. -select n_live_tup, n_dead_tup from pg_stat_all_tables_internal where relid = 'table_for_truncate_abort'::regclass; +select gp_stat_force_next_flush(); +select n_live_tup, n_dead_tup from gp_stat_all_tables_summary where relid = 'table_for_truncate_abort'::regclass; -- Test pgstat table stat for partition table on QD @@ -170,18 +170,18 @@ PARTITION BY RANGE (rank) ( START (1) END (10) EVERY (5), DEFAULT PARTITION extra ); insert into rankpart select i, i % 10, i from generate_series(1, 1000)i; -select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'rankpart_1_prt_2'::regclass; -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'rankpart_1_prt_3'::regclass; -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'rankpart_1_prt_extra'::regclass; +select gp_stat_force_next_flush(); +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from gp_stat_all_tables_summary where relid = 'rankpart_1_prt_2'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from gp_stat_all_tables_summary where relid = 'rankpart_1_prt_3'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from gp_stat_all_tables_summary where relid = 'rankpart_1_prt_extra'::regclass; begin; delete from rankpart where id <= 100; rollback; -select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'rankpart_1_prt_2'::regclass; -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'rankpart_1_prt_3'::regclass; -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'rankpart_1_prt_extra'::regclass; +select gp_stat_force_next_flush(); +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from gp_stat_all_tables_summary where relid = 'rankpart_1_prt_2'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from gp_stat_all_tables_summary where relid = 'rankpart_1_prt_3'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from gp_stat_all_tables_summary where relid = 'rankpart_1_prt_extra'::regclass; copy rankpart (id, rank, product) from stdin; 1001 1 1001 @@ -195,9 +195,9 @@ copy rankpart (id, rank, product) from stdin; 1009 6 1009 1010 6 1010 \. -select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'rankpart_1_prt_2'::regclass; -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'rankpart_1_prt_3'::regclass; +select gp_stat_force_next_flush(); +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from gp_stat_all_tables_summary where relid = 'rankpart_1_prt_2'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from gp_stat_all_tables_summary where relid = 'rankpart_1_prt_3'::regclass; begin; update rankpart set rank = 1 where id > 1005; @@ -208,34 +208,34 @@ delete from rankpart where id > 1005; release savepoint level2; rollback to savepoint level1; commit; -select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'rankpart_1_prt_2'::regclass; -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'rankpart_1_prt_3'::regclass; -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'rankpart_1_prt_extra'::regclass; +select gp_stat_force_next_flush(); +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from gp_stat_all_tables_summary where relid = 'rankpart_1_prt_2'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from gp_stat_all_tables_summary where relid = 'rankpart_1_prt_3'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from gp_stat_all_tables_summary where relid = 'rankpart_1_prt_extra'::regclass; begin; savepoint level1_1; insert into rankpart select i, i % 10, i from generate_series(2001, 3000)i; insert into rankpart select i, i % 10, i from generate_series(3001, 4000)i; commit; -select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'rankpart_1_prt_2'::regclass; -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'rankpart_1_prt_3'::regclass; -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'rankpart_1_prt_extra'::regclass; +select gp_stat_force_next_flush(); +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from gp_stat_all_tables_summary where relid = 'rankpart_1_prt_2'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from gp_stat_all_tables_summary where relid = 'rankpart_1_prt_3'::regclass; +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from gp_stat_all_tables_summary where relid = 'rankpart_1_prt_extra'::regclass; -- Test pgstat matview stat with distributed policy. create table base_table(i int, j int, z int ) distributed by (i); insert into base_table select i,i,i from generate_series(1, 100) i; create materialized view mt as select * from base_table where z>=50; -select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'mt'::regclass; +select gp_stat_force_next_flush(); +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from gp_stat_all_tables_summary where relid = 'mt'::regclass; insert into base_table select i,i,i from generate_series(1, 100) i; refresh materialized view mt; -select pg_sleep(0.77) from gp_dist_random('gp_id'); -- Force pgstat_report_stat() to send tabstat. -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'mt'::regclass; --- pg_stat_all_tables collects gpstats across segments -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables where relid = 'mt'::regclass; +select gp_stat_force_next_flush(); +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from gp_stat_all_tables_summary where relid = 'mt'::regclass; +-- gp_stat_all_tables_summary collects gpstats across segments +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from gp_stat_all_tables_summary where relid = 'mt'::regclass; drop materialized view mt; drop table base_table; @@ -244,14 +244,14 @@ drop table base_table; create table base_table(i int, j int, z int ) distributed replicated; insert into base_table select i,i,i from generate_series(1, 100) i; create materialized view mt as select * from base_table where z>=50 distributed replicated; -select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'mt'::regclass; +select gp_stat_force_next_flush(); +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from gp_stat_all_tables_summary where relid = 'mt'::regclass; insert into base_table select i,i,i from generate_series(1, 100) i; refresh materialized view mt; -select pg_sleep(0.77) from gp_dist_random('gp_id'); -- Force pgstat_report_stat() to send tabstat. -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables_internal where relid = 'mt'::regclass; --- pg_stat_all_tables collects gpstats across segments -select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from pg_stat_all_tables where relid = 'mt'::regclass; +select gp_stat_force_next_flush(); +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from gp_stat_all_tables_summary where relid = 'mt'::regclass; +-- gp_stat_all_tables_summary collects gpstats across segments +select n_tup_ins, n_tup_upd, n_tup_del, n_tup_hot_upd, n_live_tup, n_dead_tup, n_mod_since_analyze from gp_stat_all_tables_summary where relid = 'mt'::regclass; reset gp_autostats_mode; @@ -261,17 +261,17 @@ create table tabstat_ao(i int, j int) using ao_row distributed by (i); create index on tabstat_ao(i); insert into tabstat_ao select 1,1; delete from tabstat_ao; -select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. +select gp_stat_force_next_flush(); -select count(*) from pg_stat_all_tables +select count(*) from gp_stat_all_tables_summary where relid = (select segrelid from pg_appendonly where relid = 'tabstat_ao'::regclass) OR relid = (select blkdirrelid from pg_appendonly where relid = 'tabstat_ao'::regclass) OR relid = (select visimaprelid from pg_appendonly where relid = 'tabstat_ao'::regclass); -select pg_sleep(0.77); -- Force pgstat_report_stat() to send tabstat. -select n_tup_ins from pg_stat_all_tables where relid = (select segrelid from pg_appendonly where relid = 'tabstat_ao'::regclass); -select n_tup_ins from pg_stat_all_tables where relid = (select blkdirrelid from pg_appendonly where relid = 'tabstat_ao'::regclass); -select n_tup_ins from pg_stat_all_tables where relid = (select visimaprelid from pg_appendonly where relid = 'tabstat_ao'::regclass); +select gp_stat_force_next_flush(); +select n_tup_ins from gp_stat_all_tables_summary where relid = (select segrelid from pg_appendonly where relid = 'tabstat_ao'::regclass); +select n_tup_ins from gp_stat_all_tables_summary where relid = (select blkdirrelid from pg_appendonly where relid = 'tabstat_ao'::regclass); +select n_tup_ins from gp_stat_all_tables_summary where relid = (select visimaprelid from pg_appendonly where relid = 'tabstat_ao'::regclass); drop table tabstat_ao; diff --git a/src/test/regress/sql/runtime_stats.sql b/src/test/regress/sql/runtime_stats.sql index 7fc2cbfc364..ffb66e0520b 100644 --- a/src/test/regress/sql/runtime_stats.sql +++ b/src/test/regress/sql/runtime_stats.sql @@ -3,18 +3,17 @@ -- -- Examines if run-time statistics are correct. -- - -- Returns 1 if workfiles are spilled during query execution; 0 otherwise. create or replace function isSpilling(explain_query text) returns int as $$ rv = plpy.execute(explain_query) -search_text = 'Workfile: (' +search_text = 'Disk:' result = 0 for i in range(len(rv)): cur_line = rv[i]['QUERY PLAN'] if search_text.lower() in cur_line.lower(): - str_trim = cur_line.split('Workfile: (') - str_trim = str_trim[1].split(' spilling') + str_trim = cur_line.split('Disk: ') + str_trim = str_trim[1].split('kB') if int(str_trim[0]) > 0: result = 1 return result diff --git a/src/test/regress/sql/stats.sql b/src/test/regress/sql/stats.sql index c4afe1d10f3..f59a8fdced7 100644 --- a/src/test/regress/sql/stats.sql +++ b/src/test/regress/sql/stats.sql @@ -25,11 +25,14 @@ SET LOCAL stats_fetch_consistency = snapshot; CREATE TABLE prevstats AS SELECT t.seq_scan, t.seq_tup_read, t.idx_scan, t.idx_tup_fetch, (b.heap_blks_read + b.heap_blks_hit) AS heap_blks, - (b.idx_blks_read + b.idx_blks_hit) AS idx_blks, - pg_stat_get_snapshot_timestamp() as snap_ts - FROM pg_catalog.pg_stat_user_tables AS t, + (b.idx_blks_read + b.idx_blks_hit) AS idx_blks + FROM pg_catalog.gp_stat_user_tables_summary AS t, pg_catalog.pg_statio_user_tables AS b WHERE t.relname='tenk2' AND b.relname='tenk2'; +-- start_ignore +SELECT seq_scan FROM gp_stat_user_tables_summary WHERE relname='tenk2'; +-- end_ignore +SELECT gp_stat_get_snapshot_timestamp() AS prv_snapshot_ts \gset COMMIT; -- test effects of TRUNCATE on n_live_tup/n_dead_tup counters @@ -104,21 +107,21 @@ SELECT * FROM tenk2 where unique1 = 10; RESET enable_bitmapscan; -- ensure pending stats are flushed -SELECT pg_stat_force_next_flush(); +SELECT gp_stat_force_next_flush(); -- check effects BEGIN; SET LOCAL stats_fetch_consistency = snapshot; SELECT relname, n_tup_ins, n_tup_upd, n_tup_del, n_live_tup, n_dead_tup - FROM pg_stat_user_tables + FROM gp_stat_user_tables_summary WHERE relname like 'trunc_stats_test%' order by relname; SELECT st.seq_scan >= pr.seq_scan + 1, st.seq_tup_read >= pr.seq_tup_read + cl.reltuples, st.idx_scan >= pr.idx_scan + 1, st.idx_tup_fetch >= pr.idx_tup_fetch + 1 - FROM pg_stat_user_tables AS st, pg_class AS cl, prevstats AS pr + FROM gp_stat_user_tables_summary AS st, pg_class AS cl, prevstats AS pr WHERE st.relname='tenk2' AND cl.relname='tenk2'; -- GPDB_13_MERGE_FIXME: Some statistics are handled by stat collector process on each segment but not sent to master. @@ -128,8 +131,7 @@ SELECT (SELECT sum(st.heap_blks_read) + sum(st.heap_blks_hit) - sum(pr.heap_blks FROM gp_dist_random('pg_statio_user_tables') AS st, gp_dist_random('prevstats') AS pr WHERE st.relname='tenk2') > (select relpages from pg_class where relname='tenk2'); -SELECT pr.snap_ts < pg_stat_get_snapshot_timestamp() as snapshot_newer -FROM prevstats AS pr; +SELECT :'prv_snapshot_ts' < pg_stat_get_snapshot_timestamp() as snapshot_newer; COMMIT; @@ -170,7 +172,7 @@ BEGIN; SELECT stats_test_func2(); ROLLBACK; -SELECT pg_stat_force_next_flush(); +SELECT gp_stat_force_next_flush(); -- check collected stats SELECT funcname, calls FROM pg_stat_user_functions WHERE funcid = :stats_test_func1_oid; @@ -223,75 +225,75 @@ CREATE TABLE drop_stats_test_subxact(); INSERT INTO drop_stats_test_subxact DEFAULT VALUES; SELECT 'drop_stats_test_subxact'::regclass::oid AS drop_stats_test_subxact_oid \gset -SELECT pg_stat_force_next_flush(); +SELECT gp_stat_force_next_flush(); -SELECT pg_stat_get_live_tuples(:drop_stats_test_oid); +SELECT n_live_tup FROM gp_stat_all_tables_summary WHERE relid = :drop_stats_test_oid; DROP TABLE drop_stats_test; -SELECT pg_stat_get_live_tuples(:drop_stats_test_oid); -SELECT pg_stat_get_xact_tuples_inserted(:drop_stats_test_oid); +SELECT n_live_tup FROM gp_stat_all_tables_summary WHERE relid = :drop_stats_test_oid; +SELECT n_tup_ins FROM gp_stat_xact_all_tables_summary where relid = :drop_stats_test_oid; -- check that rollback protects against having stats dropped and that local -- modifications don't pose a problem -SELECT pg_stat_get_live_tuples(:drop_stats_test_xact_oid); -SELECT pg_stat_get_tuples_inserted(:drop_stats_test_xact_oid); -SELECT pg_stat_get_xact_tuples_inserted(:drop_stats_test_xact_oid); +SELECT n_live_tup FROM gp_stat_all_tables_summary WHERE relid = :drop_stats_test_xact_oid; +SELECT n_tup_ins FROM gp_stat_all_tables_summary WHERE relid = :drop_stats_test_xact_oid; +SELECT n_tup_ins FROM gp_stat_xact_all_tables_summary where relid = :drop_stats_test_xact_oid; BEGIN; INSERT INTO drop_stats_test_xact DEFAULT VALUES; -SELECT pg_stat_get_xact_tuples_inserted(:drop_stats_test_xact_oid); +SELECT n_tup_ins FROM gp_stat_xact_all_tables_summary where relid = :drop_stats_test_xact_oid; DROP TABLE drop_stats_test_xact; -SELECT pg_stat_get_xact_tuples_inserted(:drop_stats_test_xact_oid); +SELECT n_tup_ins FROM gp_stat_xact_all_tables_summary where relid = :drop_stats_test_xact_oid; ROLLBACK; -SELECT pg_stat_force_next_flush(); -SELECT pg_stat_get_live_tuples(:drop_stats_test_xact_oid); -SELECT pg_stat_get_tuples_inserted(:drop_stats_test_xact_oid); +SELECT gp_stat_force_next_flush(); +SELECT n_live_tup FROM gp_stat_all_tables_summary WHERE relid = :drop_stats_test_xact_oid; +SELECT n_tup_ins FROM gp_stat_all_tables_summary WHERE relid = :drop_stats_test_xact_oid; -- transactional drop -SELECT pg_stat_get_live_tuples(:drop_stats_test_xact_oid); -SELECT pg_stat_get_tuples_inserted(:drop_stats_test_xact_oid); +SELECT n_live_tup FROM gp_stat_all_tables_summary WHERE relid = :drop_stats_test_xact_oid; +SELECT n_tup_ins FROM gp_stat_all_tables_summary WHERE relid = :drop_stats_test_xact_oid; BEGIN; INSERT INTO drop_stats_test_xact DEFAULT VALUES; -SELECT pg_stat_get_xact_tuples_inserted(:drop_stats_test_xact_oid); +SELECT n_tup_ins FROM gp_stat_xact_all_tables_summary where relid = :drop_stats_test_xact_oid; DROP TABLE drop_stats_test_xact; -SELECT pg_stat_get_xact_tuples_inserted(:drop_stats_test_xact_oid); +SELECT n_tup_ins FROM gp_stat_xact_all_tables_summary where relid = :drop_stats_test_xact_oid; COMMIT; -SELECT pg_stat_force_next_flush(); -SELECT pg_stat_get_live_tuples(:drop_stats_test_xact_oid); -SELECT pg_stat_get_tuples_inserted(:drop_stats_test_xact_oid); +SELECT gp_stat_force_next_flush(); +SELECT n_live_tup FROM gp_stat_all_tables_summary WHERE relid = :drop_stats_test_xact_oid; +SELECT n_tup_ins FROM gp_stat_all_tables_summary WHERE relid = :drop_stats_test_xact_oid; -- savepoint rollback (2 levels) -SELECT pg_stat_get_live_tuples(:drop_stats_test_subxact_oid); +SELECT n_live_tup FROM gp_stat_all_tables_summary WHERE relid = :drop_stats_test_subxact_oid; BEGIN; INSERT INTO drop_stats_test_subxact DEFAULT VALUES; SAVEPOINT sp1; INSERT INTO drop_stats_test_subxact DEFAULT VALUES; -SELECT pg_stat_get_xact_tuples_inserted(:drop_stats_test_subxact_oid); +SELECT n_tup_ins FROM gp_stat_xact_all_tables_summary where relid = :drop_stats_test_subxact_oid; SAVEPOINT sp2; DROP TABLE drop_stats_test_subxact; ROLLBACK TO SAVEPOINT sp2; -SELECT pg_stat_get_xact_tuples_inserted(:drop_stats_test_subxact_oid); +SELECT n_tup_ins FROM gp_stat_xact_all_tables_summary where relid = :drop_stats_test_subxact_oid; COMMIT; -SELECT pg_stat_force_next_flush(); -SELECT pg_stat_get_live_tuples(:drop_stats_test_subxact_oid); +SELECT gp_stat_force_next_flush(); +SELECT n_live_tup FROM gp_stat_all_tables_summary WHERE relid = :drop_stats_test_subxact_oid; -- savepoint rolback (1 level) -SELECT pg_stat_get_live_tuples(:drop_stats_test_subxact_oid); +SELECT n_live_tup FROM gp_stat_all_tables_summary WHERE relid = :drop_stats_test_subxact_oid; BEGIN; SAVEPOINT sp1; DROP TABLE drop_stats_test_subxact; SAVEPOINT sp2; ROLLBACK TO SAVEPOINT sp1; COMMIT; -SELECT pg_stat_get_live_tuples(:drop_stats_test_subxact_oid); +SELECT n_live_tup FROM gp_stat_all_tables_summary WHERE relid = :drop_stats_test_subxact_oid; -- and now actually drop -SELECT pg_stat_get_live_tuples(:drop_stats_test_subxact_oid); +SELECT n_live_tup FROM gp_stat_all_tables_summary WHERE relid = :drop_stats_test_subxact_oid; BEGIN; SAVEPOINT sp1; DROP TABLE drop_stats_test_subxact; SAVEPOINT sp2; RELEASE SAVEPOINT sp1; COMMIT; -SELECT pg_stat_get_live_tuples(:drop_stats_test_subxact_oid); +SELECT n_live_tup FROM gp_stat_all_tables_summary WHERE relid = :drop_stats_test_subxact_oid; DROP TABLE trunc_stats_test, trunc_stats_test1, trunc_stats_test2, trunc_stats_test3, trunc_stats_test4; DROP TABLE prevstats; @@ -309,12 +311,12 @@ DROP TABLE prevstats; BEGIN; CREATE TEMPORARY TABLE test_last_scan(idx_col int primary key, noidx_col int); INSERT INTO test_last_scan(idx_col, noidx_col) VALUES(1, 1); -SELECT pg_stat_force_next_flush(); -SELECT last_seq_scan, last_idx_scan FROM pg_stat_all_tables WHERE relid = 'test_last_scan'::regclass; +SELECT gp_stat_force_next_flush(); +SELECT last_seq_scan, last_idx_scan FROM gp_stat_all_tables_summary WHERE relid = 'test_last_scan'::regclass; COMMIT; -SELECT pg_stat_reset_single_table_counters('test_last_scan'::regclass); -SELECT seq_scan, idx_scan FROM pg_stat_all_tables WHERE relid = 'test_last_scan'::regclass; +SELECT gp_stat_reset_single_table_counters('test_last_scan'::regclass); +SELECT seq_scan, idx_scan FROM gp_stat_all_tables_summary WHERE relid = 'test_last_scan'::regclass; -- ensure we start out with exactly one index and sequential scan BEGIN; @@ -326,12 +328,12 @@ SELECT count(*) FROM test_last_scan WHERE noidx_col = 1; SET LOCAL enable_seqscan TO off; EXPLAIN (COSTS off) SELECT count(*) FROM test_last_scan WHERE idx_col = 1; SELECT count(*) FROM test_last_scan WHERE idx_col = 1; -SELECT pg_stat_force_next_flush(); +SELECT gp_stat_force_next_flush(); COMMIT; -- fetch timestamps from before the next test SELECT last_seq_scan AS test_last_seq, last_idx_scan AS test_last_idx -FROM pg_stat_all_tables WHERE relid = 'test_last_scan'::regclass \gset +FROM gp_stat_all_tables_summary WHERE relid = 'test_last_scan'::regclass \gset SELECT pg_sleep(0.1); -- assume a minimum timestamp granularity of 100ms -- cause one sequential scan @@ -341,15 +343,15 @@ SET LOCAL enable_indexscan TO off; SET LOCAL enable_bitmapscan TO off; EXPLAIN (COSTS off) SELECT count(*) FROM test_last_scan WHERE noidx_col = 1; SELECT count(*) FROM test_last_scan WHERE noidx_col = 1; -SELECT pg_stat_force_next_flush(); +SELECT gp_stat_force_next_flush(); COMMIT; -- check that just sequential scan stats were incremented SELECT seq_scan, :'test_last_seq' < last_seq_scan AS seq_ok, idx_scan, :'test_last_idx' = last_idx_scan AS idx_ok -FROM pg_stat_all_tables WHERE relid = 'test_last_scan'::regclass; +FROM gp_stat_all_tables_summary WHERE relid = 'test_last_scan'::regclass; -- fetch timestamps from before the next test SELECT last_seq_scan AS test_last_seq, last_idx_scan AS test_last_idx -FROM pg_stat_all_tables WHERE relid = 'test_last_scan'::regclass \gset +FROM gp_stat_all_tables_summary WHERE relid = 'test_last_scan'::regclass \gset SELECT pg_sleep(0.1); -- cause one index scan @@ -359,15 +361,15 @@ SET LOCAL enable_indexscan TO on; SET LOCAL enable_bitmapscan TO off; EXPLAIN (COSTS off) SELECT count(*) FROM test_last_scan WHERE idx_col = 1; SELECT count(*) FROM test_last_scan WHERE idx_col = 1; -SELECT pg_stat_force_next_flush(); +SELECT gp_stat_force_next_flush(); COMMIT; -- check that just index scan stats were incremented SELECT seq_scan, :'test_last_seq' = last_seq_scan AS seq_ok, idx_scan, :'test_last_idx' < last_idx_scan AS idx_ok -FROM pg_stat_all_tables WHERE relid = 'test_last_scan'::regclass; +FROM gp_stat_all_tables_summary WHERE relid = 'test_last_scan'::regclass; -- fetch timestamps from before the next test SELECT last_seq_scan AS test_last_seq, last_idx_scan AS test_last_idx -FROM pg_stat_all_tables WHERE relid = 'test_last_scan'::regclass \gset +FROM gp_stat_all_tables_summary WHERE relid = 'test_last_scan'::regclass \gset SELECT pg_sleep(0.1); -- cause one bitmap index scan @@ -377,11 +379,11 @@ SET LOCAL enable_indexscan TO off; SET LOCAL enable_bitmapscan TO on; EXPLAIN (COSTS off) SELECT count(*) FROM test_last_scan WHERE idx_col = 1; SELECT count(*) FROM test_last_scan WHERE idx_col = 1; -SELECT pg_stat_force_next_flush(); +SELECT gp_stat_force_next_flush(); COMMIT; -- check that just index scan stats were incremented SELECT seq_scan, :'test_last_seq' = last_seq_scan AS seq_ok, idx_scan, :'test_last_idx' < last_idx_scan AS idx_ok -FROM pg_stat_all_tables WHERE relid = 'test_last_scan'::regclass; +FROM gp_stat_all_tables_summary WHERE relid = 'test_last_scan'::regclass; ----- -- Test reset of some stats for shared table @@ -397,14 +399,14 @@ SELECT shobj_description(d.oid, 'pg_database') as description_before BEGIN; SELECT current_database() as datname \gset COMMENT ON DATABASE :"datname" IS 'This is a test comment'; -SELECT pg_stat_force_next_flush(); +SELECT gp_stat_force_next_flush(); COMMIT; -- check that the stats are reset. -SELECT (n_tup_ins + n_tup_upd) > 0 AS has_data FROM pg_stat_all_tables +SELECT (n_tup_ins + n_tup_upd) > 0 AS has_data FROM gp_stat_all_tables_summary WHERE relid = 'pg_shdescription'::regclass; -SELECT pg_stat_reset_single_table_counters('pg_shdescription'::regclass); -SELECT (n_tup_ins + n_tup_upd) > 0 AS has_data FROM pg_stat_all_tables +SELECT gp_stat_reset_single_table_counters('pg_shdescription'::regclass); +SELECT (n_tup_ins + n_tup_upd) > 0 AS has_data FROM gp_stat_all_tables_summary WHERE relid = 'pg_shdescription'::regclass; -- set back comment @@ -421,7 +423,7 @@ SELECT (n_tup_ins + n_tup_upd) > 0 AS has_data FROM pg_stat_all_tables -- 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 pg_stat_force_next_flush(); +SELECT gp_stat_force_next_flush(); 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 @@ -445,9 +447,10 @@ SELECT wal_bytes > :wal_bytes_before FROM pg_stat_wal; -- Test pg_stat_get_backend_idset() and some allied functions. -- In particular, verify that their notion of backend ID matches -- our temp schema index. -SELECT (current_schemas(true))[1] = ('pg_temp_' || beid::text) AS match -FROM pg_stat_get_backend_idset() beid -WHERE pg_stat_get_backend_pid(beid) = pg_backend_pid(); +-- In CBDB temp schema use ('pg_temp_' || gp_session_id::text) +-- SELECT (current_schemas(true))[1] = ('pg_temp_' || beid::text) AS match +-- FROM pg_stat_get_backend_idset() beid +-- WHERE pg_stat_get_backend_pid(beid) = pg_backend_pid(); ----- -- Test that resetting stats works for reset timestamp @@ -467,24 +470,24 @@ SELECT stats_reset > :'slru_notify_reset_ts'::timestamptz FROM pg_stat_slru WHER -- 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 gp_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 gp_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 gp_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 gp_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; @@ -593,7 +596,7 @@ SELECT pg_stat_get_replication_slot(NULL); SELECT pg_stat_get_subscription_stats(NULL); --- Test that the following operations are tracked in pg_stat_io: +-- Test that the following operations are tracked in gp_stat_io_summary: -- - reads of target blocks into shared buffers -- - writes of shared buffers to permanent storage -- - extends of relations using shared buffers @@ -606,15 +609,15 @@ SELECT pg_stat_get_subscription_stats(NULL); -- Create a regular table and insert some data to generate IOCONTEXT_NORMAL -- extends. SELECT sum(extends) AS io_sum_shared_before_extends - FROM pg_stat_io WHERE context = 'normal' AND object = 'relation' \gset + FROM gp_stat_io_summary WHERE context = 'normal' AND object = 'relation' \gset SELECT sum(writes) AS writes, sum(fsyncs) AS fsyncs - FROM pg_stat_io + FROM gp_stat_io_summary WHERE object = 'relation' \gset io_sum_shared_before_ CREATE TABLE test_io_shared(a int); INSERT INTO test_io_shared SELECT i FROM generate_series(1,100)i; -SELECT pg_stat_force_next_flush(); +SELECT gp_stat_force_next_flush(); SELECT sum(extends) AS io_sum_shared_after_extends - FROM pg_stat_io WHERE context = 'normal' AND object = 'relation' \gset + FROM gp_stat_io_summary WHERE context = 'normal' AND object = 'relation' \gset SELECT :io_sum_shared_after_extends > :io_sum_shared_before_extends; -- After a checkpoint, there should be some additional IOCONTEXT_NORMAL writes @@ -623,7 +626,7 @@ SELECT :io_sum_shared_after_extends > :io_sum_shared_before_extends; CHECKPOINT; CHECKPOINT; SELECT sum(writes) AS writes, sum(fsyncs) AS fsyncs - FROM pg_stat_io + FROM gp_stat_io_summary WHERE object = 'relation' \gset io_sum_shared_after_ SELECT :io_sum_shared_after_writes > :io_sum_shared_before_writes; SELECT current_setting('fsync') = 'off' @@ -632,7 +635,7 @@ SELECT current_setting('fsync') = 'off' -- Change the tablespace so that the table is rewritten directly, then SELECT -- from it to cause it to be read back into shared buffers. SELECT sum(reads) AS io_sum_shared_before_reads - FROM pg_stat_io WHERE context = 'normal' AND object = 'relation' \gset + FROM gp_stat_io_summary WHERE context = 'normal' AND object = 'relation' \gset -- Do this in a transaction to prevent spurious failures due to concurrent accesses to our newly -- rewritten table, e.g. by autovacuum. BEGIN; @@ -641,13 +644,13 @@ ALTER TABLE test_io_shared SET TABLESPACE regress_tblspace; -- context 'normal', object 'relation' reads are counted. SELECT COUNT(*) FROM test_io_shared; COMMIT; -SELECT pg_stat_force_next_flush(); +SELECT gp_stat_force_next_flush(); SELECT sum(reads) AS io_sum_shared_after_reads - FROM pg_stat_io WHERE context = 'normal' AND object = 'relation' \gset + FROM gp_stat_io_summary WHERE context = 'normal' AND object = 'relation' \gset SELECT :io_sum_shared_after_reads > :io_sum_shared_before_reads; SELECT sum(hits) AS io_sum_shared_before_hits - FROM pg_stat_io WHERE context = 'normal' AND object = 'relation' \gset + FROM gp_stat_io_summary WHERE context = 'normal' AND object = 'relation' \gset -- Select from the table again to count hits. -- Ensure we generate hits by forcing a nested loop self-join with no -- materialize node. The outer side's buffer will stay pinned, preventing its @@ -659,14 +662,14 @@ SET LOCAL enable_hashjoin TO off; SET LOCAL enable_material TO off; EXPLAIN (COSTS OFF) SELECT COUNT(*) FROM test_io_shared t1 INNER JOIN test_io_shared t2 USING (a); SELECT COUNT(*) FROM test_io_shared t1 INNER JOIN test_io_shared t2 USING (a); COMMIT; -SELECT pg_stat_force_next_flush(); +SELECT gp_stat_force_next_flush(); SELECT sum(hits) AS io_sum_shared_after_hits - FROM pg_stat_io WHERE context = 'normal' AND object = 'relation' \gset + FROM gp_stat_io_summary WHERE context = 'normal' AND object = 'relation' \gset SELECT :io_sum_shared_after_hits > :io_sum_shared_before_hits; DROP TABLE test_io_shared; --- Test that the follow IOCONTEXT_LOCAL IOOps are tracked in pg_stat_io: +-- Test that the follow IOCONTEXT_LOCAL IOOps are tracked in gp_stat_io_summary: -- - eviction of local buffers in order to reuse them -- - reads of temporary table blocks into local buffers -- - writes of local buffers to permanent storage @@ -675,30 +678,33 @@ DROP TABLE test_io_shared; -- Set temp_buffers to its minimum so that we can trigger writes with fewer -- inserted tuples. Do so in a new session in case temporary tables have been -- accessed by previous tests in this session. +-- CBDB: CBDB use share buffer not local buffer.So extends with object = 'relation' not 'temp relation'. +-- read/write will not count directly, result is false \c SET temp_buffers TO 100; CREATE TEMPORARY TABLE test_io_local(a int, b TEXT); SELECT sum(extends) AS extends, sum(evictions) AS evictions, sum(writes) AS writes FROM pg_stat_io - WHERE context = 'normal' AND object = 'temp relation' \gset io_sum_local_before_ + WHERE context = 'normal' AND object = 'relation' \gset io_sum_local_before_ -- Insert tuples into the temporary table, generating extends in the stats. -- Insert enough values that we need to reuse and write out dirty local -- buffers, generating evictions and writes. -INSERT INTO test_io_local SELECT generate_series(1, 5000) as id, repeat('a', 200); +INSERT INTO test_io_local SELECT generate_series(1, 50000) as id, repeat('a', 800); -- Ensure the table is large enough to exceed our temp_buffers setting. SELECT pg_relation_size('test_io_local') / current_setting('block_size')::int8 > 100; SELECT sum(reads) AS io_sum_local_before_reads - FROM pg_stat_io WHERE context = 'normal' AND object = 'temp relation' \gset + FROM gp_stat_io_summary WHERE context = 'normal' AND object = 'relation' \gset + -- Read in evicted buffers, generating reads. SELECT COUNT(*) FROM test_io_local; -SELECT pg_stat_force_next_flush(); +SELECT gp_stat_force_next_flush(); SELECT sum(evictions) AS evictions, sum(reads) AS reads, sum(writes) AS writes, sum(extends) AS extends - FROM pg_stat_io - WHERE context = 'normal' AND object = 'temp relation' \gset io_sum_local_after_ + FROM gp_stat_io_summary + WHERE context = 'normal' AND object = 'relation' \gset io_sum_local_after_ SELECT :io_sum_local_after_evictions > :io_sum_local_before_evictions, :io_sum_local_after_reads > :io_sum_local_before_reads, :io_sum_local_after_writes > :io_sum_local_before_writes, @@ -708,14 +714,14 @@ SELECT :io_sum_local_after_evictions > :io_sum_local_before_evictions, -- local buffers, exercising a different codepath than standard local buffer -- writes. ALTER TABLE test_io_local SET TABLESPACE regress_tblspace; -SELECT pg_stat_force_next_flush(); +SELECT gp_stat_force_next_flush(); SELECT sum(writes) AS io_sum_local_new_tblspc_writes - FROM pg_stat_io WHERE context = 'normal' AND object = 'temp relation' \gset + FROM gp_stat_io_summary WHERE context = 'normal' AND object = 'relation' \gset SELECT :io_sum_local_new_tblspc_writes > :io_sum_local_after_writes; RESET temp_buffers; -- Test that reuse of strategy buffers and reads of blocks into these reused --- buffers while VACUUMing are tracked in pg_stat_io. If there is sufficient +-- buffers while VACUUMing are tracked in gp_stat_io_summary. If there is sufficient -- demand for shared buffers from concurrent queries, some buffers may be -- pinned by other backends before they can be reused. In such cases, the -- backend will evict a buffer from outside the ring and add it to the @@ -729,40 +735,40 @@ RESET temp_buffers; -- reads. SET wal_skip_threshold = '1 kB'; SELECT sum(reuses) AS reuses, sum(reads) AS reads, sum(evictions) AS evictions - FROM pg_stat_io WHERE context = 'vacuum' \gset io_sum_vac_strategy_before_ + FROM gp_stat_io_summary WHERE context = 'vacuum' \gset io_sum_vac_strategy_before_ CREATE TABLE test_io_vac_strategy(a int, b int) WITH (autovacuum_enabled = 'false'); -INSERT INTO test_io_vac_strategy SELECT i, i from generate_series(1, 4500)i; +INSERT INTO test_io_vac_strategy SELECT i, i from generate_series(1, 45000)i; -- Ensure that the next VACUUM will need to perform IO by rewriting the table -- first with VACUUM (FULL). VACUUM (FULL) test_io_vac_strategy; -- Use the minimum BUFFER_USAGE_LIMIT to cause reuses or evictions with the -- smallest table possible. VACUUM (PARALLEL 0, BUFFER_USAGE_LIMIT 128) test_io_vac_strategy; -SELECT pg_stat_force_next_flush(); +SELECT gp_stat_force_next_flush(); SELECT sum(reuses) AS reuses, sum(reads) AS reads, sum(evictions) AS evictions - FROM pg_stat_io WHERE context = 'vacuum' \gset io_sum_vac_strategy_after_ + FROM gp_stat_io_summary WHERE context = 'vacuum' \gset io_sum_vac_strategy_after_ SELECT :io_sum_vac_strategy_after_reads > :io_sum_vac_strategy_before_reads; SELECT (:io_sum_vac_strategy_after_reuses + :io_sum_vac_strategy_after_evictions) > (:io_sum_vac_strategy_before_reuses + :io_sum_vac_strategy_before_evictions); RESET wal_skip_threshold; -- Test that extends done by a CTAS, which uses a BAS_BULKWRITE --- BufferAccessStrategy, are tracked in pg_stat_io. +-- BufferAccessStrategy, are tracked in gp_stat_io_summary. SELECT sum(extends) AS io_sum_bulkwrite_strategy_extends_before - FROM pg_stat_io WHERE context = 'bulkwrite' \gset + FROM gp_stat_io_summary WHERE context = 'bulkwrite' \gset CREATE TABLE test_io_bulkwrite_strategy AS SELECT i FROM generate_series(1,100)i; -SELECT pg_stat_force_next_flush(); +SELECT gp_stat_force_next_flush(); SELECT sum(extends) AS io_sum_bulkwrite_strategy_extends_after - FROM pg_stat_io WHERE context = 'bulkwrite' \gset + FROM gp_stat_io_summary WHERE context = 'bulkwrite' \gset SELECT :io_sum_bulkwrite_strategy_extends_after > :io_sum_bulkwrite_strategy_extends_before; -- Test IO stats reset SELECT pg_stat_have_stats('io', 0, 0); SELECT sum(evictions) + sum(reuses) + sum(extends) + sum(fsyncs) + sum(reads) + sum(writes) + sum(writebacks) + sum(hits) AS io_stats_pre_reset - FROM pg_stat_io \gset -SELECT pg_stat_reset_shared('io'); + FROM gp_stat_io_summary \gset +SELECT gp_stat_reset_shared('io'); SELECT sum(evictions) + sum(reuses) + sum(extends) + sum(fsyncs) + sum(reads) + sum(writes) + sum(writebacks) + sum(hits) AS io_stats_post_reset - FROM pg_stat_io \gset + FROM gp_stat_io_summary \gset SELECT :io_stats_post_reset < :io_stats_pre_reset; @@ -782,7 +788,7 @@ DECLARE BEGIN -- we don't want to wait forever; loop will exit after 30 seconds FOR i IN 1 .. 300 LOOP - SELECT (pg_stat_get_tuples_hot_updated('brin_hot'::regclass::oid) > 0) INTO updated; + SELECT n_tup_upd > 0 INTO updated FROM gp_stat_user_tables_summary WHERE relid = ('brin_hot'::regclass::oid); EXIT WHEN updated; -- wait a little @@ -807,7 +813,7 @@ UPDATE brin_hot SET val = -3 WHERE id = 42; \c - SELECT wait_for_hot_stats(); -SELECT pg_stat_get_tuples_hot_updated('brin_hot'::regclass::oid); +select n_tup_upd from gp_stat_user_tables_summary where relid = ('brin_hot'::regclass::oid); DROP TABLE brin_hot; DROP FUNCTION wait_for_hot_stats();