mirror of
https://github.com/postgres/postgres.git
synced 2025-06-10 09:21:54 +03:00
pgstat: Fix transactional stats dropping for indexes
Because index creation does not go through heap_create_with_catalog() we
didn't call pgstat_create_relation(), leading to index stats of a newly
created realtion not getting dropped during rollback. To fix, move the
pgstat_create_relation() to heap_create(), which indexes do use.
Similarly, because dropping an index does not go through
heap_drop_with_catalog(), we didn't drop index stats when the transaction
dropping an index committed. Here there's no convenient common path for
indexes and relations, so index_drop() now calls pgstat_drop_relation().
Add tests for transactional index stats handling.
Author: "Drouvot, Bertrand" <bdrouvot@amazon.com>
Reviewed-by: Andres Freund <andres@anarazel.de>
Reviewed-by: Kyotaro Horiguchi <horikyota.ntt@gmail.com>
Discussion: https://postgr.es/m/51bbf286-2b4a-8998-bd12-eaae4b765d99@amazon.com
Backpatch: 15-, like 8b1dccd37c
, which introduced the bug
This commit is contained in:
@ -403,6 +403,9 @@ heap_create(const char *relname,
|
|||||||
recordDependencyOnTablespace(RelationRelationId, relid,
|
recordDependencyOnTablespace(RelationRelationId, relid,
|
||||||
reltablespace);
|
reltablespace);
|
||||||
|
|
||||||
|
/* ensure that stats are dropped if transaction aborts */
|
||||||
|
pgstat_create_relation(rel);
|
||||||
|
|
||||||
return rel;
|
return rel;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1477,9 +1480,6 @@ heap_create_with_catalog(const char *relname,
|
|||||||
if (oncommit != ONCOMMIT_NOOP)
|
if (oncommit != ONCOMMIT_NOOP)
|
||||||
register_on_commit_action(relid, oncommit);
|
register_on_commit_action(relid, oncommit);
|
||||||
|
|
||||||
/* ensure that stats are dropped if transaction aborts */
|
|
||||||
pgstat_create_relation(new_rel_desc);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ok, the relation has been cataloged, so close our relations and return
|
* ok, the relation has been cataloged, so close our relations and return
|
||||||
* the OID of the newly created relation.
|
* the OID of the newly created relation.
|
||||||
|
@ -2325,6 +2325,9 @@ index_drop(Oid indexId, bool concurrent, bool concurrent_lock_mode)
|
|||||||
if (RELKIND_HAS_STORAGE(userIndexRelation->rd_rel->relkind))
|
if (RELKIND_HAS_STORAGE(userIndexRelation->rd_rel->relkind))
|
||||||
RelationDropStorage(userIndexRelation);
|
RelationDropStorage(userIndexRelation);
|
||||||
|
|
||||||
|
/* ensure that stats are dropped if transaction commits */
|
||||||
|
pgstat_drop_relation(userIndexRelation);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Close and flush the index's relcache entry, to ensure relcache doesn't
|
* Close and flush the index's relcache entry, to ensure relcache doesn't
|
||||||
* try to rebuild it while we're deleting catalog entries. We keep the
|
* try to rebuild it while we're deleting catalog entries. We keep the
|
||||||
|
@ -18,6 +18,8 @@ SET enable_indexscan TO on;
|
|||||||
SET enable_indexonlyscan TO off;
|
SET enable_indexonlyscan TO off;
|
||||||
-- not enabled by default, but we want to test it...
|
-- not enabled by default, but we want to test it...
|
||||||
SET track_functions TO 'all';
|
SET track_functions TO 'all';
|
||||||
|
-- record dboid for later use
|
||||||
|
SELECT oid AS dboid from pg_database where datname = current_database() \gset
|
||||||
-- save counters
|
-- save counters
|
||||||
BEGIN;
|
BEGIN;
|
||||||
SET LOCAL stats_fetch_consistency = snapshot;
|
SET LOCAL stats_fetch_consistency = snapshot;
|
||||||
@ -777,18 +779,121 @@ SELECT pg_stat_have_stats('bgwriter', 0, 0);
|
|||||||
SELECT pg_stat_have_stats('zaphod', 0, 0);
|
SELECT pg_stat_have_stats('zaphod', 0, 0);
|
||||||
ERROR: invalid statistics kind: "zaphod"
|
ERROR: invalid statistics kind: "zaphod"
|
||||||
-- db stats have objoid 0
|
-- db stats have objoid 0
|
||||||
SELECT pg_stat_have_stats('database', (SELECT oid FROM pg_database WHERE datname = current_database()), 1);
|
SELECT pg_stat_have_stats('database', :dboid, 1);
|
||||||
pg_stat_have_stats
|
pg_stat_have_stats
|
||||||
--------------------
|
--------------------
|
||||||
f
|
f
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
SELECT pg_stat_have_stats('database', (SELECT oid FROM pg_database WHERE datname = current_database()), 0);
|
SELECT pg_stat_have_stats('database', :dboid, 0);
|
||||||
pg_stat_have_stats
|
pg_stat_have_stats
|
||||||
--------------------
|
--------------------
|
||||||
t
|
t
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
|
-- pg_stat_have_stats returns true for committed index creation
|
||||||
|
CREATE table stats_test_tab1 as select generate_series(1,10) a;
|
||||||
|
CREATE index stats_test_idx1 on stats_test_tab1(a);
|
||||||
|
SELECT 'stats_test_idx1'::regclass::oid AS stats_test_idx1_oid \gset
|
||||||
|
SET enable_seqscan TO off;
|
||||||
|
select a from stats_test_tab1 where a = 3;
|
||||||
|
a
|
||||||
|
---
|
||||||
|
3
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid);
|
||||||
|
pg_stat_have_stats
|
||||||
|
--------------------
|
||||||
|
t
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- pg_stat_have_stats returns false for dropped index with stats
|
||||||
|
SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid);
|
||||||
|
pg_stat_have_stats
|
||||||
|
--------------------
|
||||||
|
t
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
DROP index stats_test_idx1;
|
||||||
|
SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid);
|
||||||
|
pg_stat_have_stats
|
||||||
|
--------------------
|
||||||
|
f
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- pg_stat_have_stats returns false for rolled back index creation
|
||||||
|
BEGIN;
|
||||||
|
CREATE index stats_test_idx1 on stats_test_tab1(a);
|
||||||
|
SELECT 'stats_test_idx1'::regclass::oid AS stats_test_idx1_oid \gset
|
||||||
|
select a from stats_test_tab1 where a = 3;
|
||||||
|
a
|
||||||
|
---
|
||||||
|
3
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid);
|
||||||
|
pg_stat_have_stats
|
||||||
|
--------------------
|
||||||
|
t
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
ROLLBACK;
|
||||||
|
SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid);
|
||||||
|
pg_stat_have_stats
|
||||||
|
--------------------
|
||||||
|
f
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- pg_stat_have_stats returns true for reindex CONCURRENTLY
|
||||||
|
CREATE index stats_test_idx1 on stats_test_tab1(a);
|
||||||
|
SELECT 'stats_test_idx1'::regclass::oid AS stats_test_idx1_oid \gset
|
||||||
|
select a from stats_test_tab1 where a = 3;
|
||||||
|
a
|
||||||
|
---
|
||||||
|
3
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid);
|
||||||
|
pg_stat_have_stats
|
||||||
|
--------------------
|
||||||
|
t
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
REINDEX index CONCURRENTLY stats_test_idx1;
|
||||||
|
-- false for previous oid
|
||||||
|
SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid);
|
||||||
|
pg_stat_have_stats
|
||||||
|
--------------------
|
||||||
|
f
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- true for new oid
|
||||||
|
SELECT 'stats_test_idx1'::regclass::oid AS stats_test_idx1_oid \gset
|
||||||
|
SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid);
|
||||||
|
pg_stat_have_stats
|
||||||
|
--------------------
|
||||||
|
t
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- pg_stat_have_stats returns true for a rolled back drop index with stats
|
||||||
|
BEGIN;
|
||||||
|
SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid);
|
||||||
|
pg_stat_have_stats
|
||||||
|
--------------------
|
||||||
|
t
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
DROP index stats_test_idx1;
|
||||||
|
ROLLBACK;
|
||||||
|
SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid);
|
||||||
|
pg_stat_have_stats
|
||||||
|
--------------------
|
||||||
|
t
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- put enable_seqscan back to on
|
||||||
|
SET enable_seqscan TO on;
|
||||||
-- ensure that stats accessors handle NULL input correctly
|
-- ensure that stats accessors handle NULL input correctly
|
||||||
SELECT pg_stat_get_replication_slot(NULL);
|
SELECT pg_stat_get_replication_slot(NULL);
|
||||||
pg_stat_get_replication_slot
|
pg_stat_get_replication_slot
|
||||||
|
@ -16,6 +16,9 @@ SET enable_indexonlyscan TO off;
|
|||||||
-- not enabled by default, but we want to test it...
|
-- not enabled by default, but we want to test it...
|
||||||
SET track_functions TO 'all';
|
SET track_functions TO 'all';
|
||||||
|
|
||||||
|
-- record dboid for later use
|
||||||
|
SELECT oid AS dboid from pg_database where datname = current_database() \gset
|
||||||
|
|
||||||
-- save counters
|
-- save counters
|
||||||
BEGIN;
|
BEGIN;
|
||||||
SET LOCAL stats_fetch_consistency = snapshot;
|
SET LOCAL stats_fetch_consistency = snapshot;
|
||||||
@ -388,9 +391,52 @@ SELECT pg_stat_have_stats('bgwriter', 0, 0);
|
|||||||
-- unknown stats kinds error out
|
-- unknown stats kinds error out
|
||||||
SELECT pg_stat_have_stats('zaphod', 0, 0);
|
SELECT pg_stat_have_stats('zaphod', 0, 0);
|
||||||
-- db stats have objoid 0
|
-- db stats have objoid 0
|
||||||
SELECT pg_stat_have_stats('database', (SELECT oid FROM pg_database WHERE datname = current_database()), 1);
|
SELECT pg_stat_have_stats('database', :dboid, 1);
|
||||||
SELECT pg_stat_have_stats('database', (SELECT oid FROM pg_database WHERE datname = current_database()), 0);
|
SELECT pg_stat_have_stats('database', :dboid, 0);
|
||||||
|
|
||||||
|
-- pg_stat_have_stats returns true for committed index creation
|
||||||
|
CREATE table stats_test_tab1 as select generate_series(1,10) a;
|
||||||
|
CREATE index stats_test_idx1 on stats_test_tab1(a);
|
||||||
|
SELECT 'stats_test_idx1'::regclass::oid AS stats_test_idx1_oid \gset
|
||||||
|
SET enable_seqscan TO off;
|
||||||
|
select a from stats_test_tab1 where a = 3;
|
||||||
|
SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid);
|
||||||
|
|
||||||
|
-- pg_stat_have_stats returns false for dropped index with stats
|
||||||
|
SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid);
|
||||||
|
DROP index stats_test_idx1;
|
||||||
|
SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid);
|
||||||
|
|
||||||
|
-- pg_stat_have_stats returns false for rolled back index creation
|
||||||
|
BEGIN;
|
||||||
|
CREATE index stats_test_idx1 on stats_test_tab1(a);
|
||||||
|
SELECT 'stats_test_idx1'::regclass::oid AS stats_test_idx1_oid \gset
|
||||||
|
select a from stats_test_tab1 where a = 3;
|
||||||
|
SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid);
|
||||||
|
ROLLBACK;
|
||||||
|
SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid);
|
||||||
|
|
||||||
|
-- pg_stat_have_stats returns true for reindex CONCURRENTLY
|
||||||
|
CREATE index stats_test_idx1 on stats_test_tab1(a);
|
||||||
|
SELECT 'stats_test_idx1'::regclass::oid AS stats_test_idx1_oid \gset
|
||||||
|
select a from stats_test_tab1 where a = 3;
|
||||||
|
SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid);
|
||||||
|
REINDEX index CONCURRENTLY stats_test_idx1;
|
||||||
|
-- false for previous oid
|
||||||
|
SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid);
|
||||||
|
-- true for new oid
|
||||||
|
SELECT 'stats_test_idx1'::regclass::oid AS stats_test_idx1_oid \gset
|
||||||
|
SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid);
|
||||||
|
|
||||||
|
-- pg_stat_have_stats returns true for a rolled back drop index with stats
|
||||||
|
BEGIN;
|
||||||
|
SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid);
|
||||||
|
DROP index stats_test_idx1;
|
||||||
|
ROLLBACK;
|
||||||
|
SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid);
|
||||||
|
|
||||||
|
-- put enable_seqscan back to on
|
||||||
|
SET enable_seqscan TO on;
|
||||||
|
|
||||||
-- ensure that stats accessors handle NULL input correctly
|
-- ensure that stats accessors handle NULL input correctly
|
||||||
SELECT pg_stat_get_replication_slot(NULL);
|
SELECT pg_stat_get_replication_slot(NULL);
|
||||||
|
Reference in New Issue
Block a user