From: Noah Misch <noah@leadboat.com>
To: pgsql-hackers@postgresql.org
Subject: pgstatindex vs. !indisready
Date: Sun, 1 Oct 2023 12:53:09 -0700
Message-ID: <20231001195309.a3@google.com> (raw)
Running pgstatindex on some !indisready indexes fails with "ERROR: XX001:
could not read block 0 in file". This reproduces it:
begin;
drop table if exists not_indisready_t;
create table not_indisready_t (c int);
insert into not_indisready_t values (1),(1);
commit;
create unique index concurrently not_indisready_i on not_indisready_t(c);
begin;
create extension pgstattuple;
\set VERBOSITY verbose
select * from pgstatindex('not_indisready_i');
\set VERBOSITY default
rollback;
Since XX001 = ERRCODE_DATA_CORRUPTED appears in the "can't-happen" class, it's
not a good fit for this scenario. I propose to have pgstatindex fail early on
!indisready indexes. We could go a step further and also fail on
indisready&&!indisvalid indexes, which are complete enough to accept inserts
but not complete enough to answer queries. I don't see a reason to do that,
but maybe someone else will.
This made me wonder about functions handling unlogged rels during recovery. I
used the attached hack to test most regclass-arg functions. While some of
these errors from src/test/recovery/tmp_check/log/001_stream_rep_standby_2.log
may deserve improvement, there were no class-XX messages:
2023-10-01 12:24:05.992 PDT [646914:11] 001_stream_rep.pl ERROR: 58P01: could not open file "base/5/16862": No such file or directory
2023-10-01 12:24:05.996 PDT [646914:118] 001_stream_rep.pl ERROR: 22023: fork "main" does not exist for this relation
Thanks,
nm
Author: Noah Misch <noah@leadboat.com>
Commit: Noah Misch <noah@leadboat.com>
diff --git a/src/test/recovery/Makefile b/src/test/recovery/Makefileindex c60314d..ad54859 100644--- a/src/test/recovery/Makefile+++ b/src/test/recovery/Makefile@@ -10,6 +10,14 @@
#-------------------------------------------------------------------------
EXTRA_INSTALL=contrib/pg_prewarm contrib/pg_stat_statements contrib/test_decoding
+EXTRA_INSTALL += \+ contrib/pg_visibility \+ contrib/amcheck \+ contrib/pgstattuple \+ contrib/btree_gin \+ contrib/pg_surgery \+ contrib/pg_freespacemap \+ contrib/pgrowlocks
subdir = src/test/recovery
top_builddir = ../../..
diff --git a/src/test/recovery/t/001_stream_rep.pl b/src/test/recovery/t/001_stream_rep.plindex 0c72ba0..e441cb2 100644--- a/src/test/recovery/t/001_stream_rep.pl+++ b/src/test/recovery/t/001_stream_rep.pl@@ -45,6 +45,24 @@ $node_standby_2->start;
# Create some content on primary and check its presence in standby nodes
$node_primary->safe_psql('postgres',
"CREATE TABLE tab_int AS SELECT generate_series(1,1002) AS a");
+$node_primary->safe_psql('postgres', "+create extension pg_visibility;+create extension amcheck;+create extension pgstattuple;+create extension btree_gin;+create extension pg_surgery;+create extension pg_prewarm;+create extension pg_freespacemap;+create extension pgrowlocks;++create unlogged sequence useq;+create unlogged table u (c text);+insert into u values ('foo');+create index ubtree on u (c);+create index ugin on u using gin (c);+create index uhash on u using hash (c);+create index ubrin on u using brin (c);+");
# Wait for standbys to catch up
$node_primary->wait_for_replay_catchup($node_standby_1);
@@ -60,6 +78,88 @@ $result =
print "standby 2: $result\n";
is($result, qq(1002), 'check streamed content on standby 2');
+# Call regclass-arg functions on unlogged objects. Function list from:+#+# DO $$+# DECLARE+# extname text;+# BEGIN+# FOR extname in SELECT name from pg_available_extensions LOOP+# EXECUTE format('CREATE EXTENSION IF NOT EXISTS %I CASCADE', extname);+# END LOOP;+# END+# $$;+# select oid::regprocedure from pg_proc+# where proargtypes::oid[] @> array['regclass'::regtype::oid]+# order by oid::regprocedure::text;+#+# Removed pageinspect functions, since the superuser might choose to run them+# in cases we wouldn't expect. Added pgrowlocks(text).+$node_standby_2->psql('postgres', <<'EOSQL', on_error_stop => 0);+\set utable '''u''::regclass'+\set VERBOSITY verbose+SET log_error_verbosity = verbose;+SET log_min_messages = debug1; -- for amcheck+SET client_min_messages = debug1;++SELECT * FROM pgrowlocks(:utable::text);+SELECT brin_desummarize_range('ubrin',1);+SELECT brin_summarize_new_values('ubrin');+SELECT brin_summarize_range('ubrin',1);+SELECT bt_index_check('ubtree');+SELECT bt_index_check('ubtree',true);+SELECT bt_index_parent_check('ubtree');+SELECT bt_index_parent_check('ubtree',true);+SELECT bt_index_parent_check('ubtree',true,true);+SELECT gin_clean_pending_list('ugin');+SELECT heap_force_freeze(:utable,array['(0,1)'::tid]);+SELECT heap_force_kill(:utable,array['(0,1)'::tid]);+SELECT nextval('useq');+SELECT currval('useq');+SELECT pg_check_frozen(:utable);+SELECT pg_check_visible(:utable);+SELECT pg_column_is_updatable(:utable,'1',true);+--SELECT pg_extension_config_dump(:utable,'select 1');+SELECT pg_freespace(:utable);+SELECT pg_freespace(:utable,1);+SELECT pg_get_replica_identity_index(:utable);+SELECT pg_index_column_has_property(:utable,1,'asc');+SELECT pg_indexes_size(:utable);+SELECT pg_index_has_property('ubrin','asc');+--SELECT pg_nextoid(:utable,name,:utable);+SELECT pg_partition_ancestors(:utable);+SELECT pg_partition_root(:utable);+SELECT pg_partition_tree(:utable);+SELECT pg_prewarm(:utable);+SELECT pg_relation_filenode(:utable);+SELECT pg_relation_filepath(:utable);+SELECT pg_relation_is_publishable(:utable);+SELECT pg_relation_is_updatable(:utable,true);+SELECT pg_relation_size(:utable);+SELECT pg_relation_size(:utable,'main');+SELECT pg_relpages(:utable);+SELECT pg_sequence_last_value('useq');+SELECT pgstatginindex('ugin');+SELECT pgstathashindex('uhash');+SELECT pgstatindex('ubtree');+SELECT pgstattuple_approx(:utable);+SELECT pgstattuple(:utable);+SELECT pg_table_size(:utable);+SELECT pg_total_relation_size(:utable);+SELECT pg_truncate_visibility_map(:utable);+SELECT pg_visibility_map(:utable);+SELECT pg_visibility_map(:utable,1);+SELECT pg_visibility_map_summary(:utable);+SELECT pg_visibility(:utable);+SELECT pg_visibility(:utable,1);+SELECT setval('useq',1);+SELECT setval('useq',1,true);+SELECT table_to_xml_and_xmlschema(:utable,true,true,'nsp');+SELECT table_to_xml(:utable,true,true,'nsp');+SELECT table_to_xmlschema(:utable,true,true,'nsp');+SELECT verify_heapam(:utable);+EOSQL+
# Likewise, but for a sequence
$node_primary->safe_psql('postgres',
"CREATE SEQUENCE seq1; SELECT nextval('seq1')");
Attachments:
[text/plain] unlogged-recovery-funcalls-v0.patch (4.9K, ../20231001195309.a3@google.com/2-unlogged-recovery-funcalls-v0.patch)
download | inline diff:
Author: Noah Misch <noah@leadboat.com>
Commit: Noah Misch <noah@leadboat.com>
diff --git a/src/test/recovery/Makefile b/src/test/recovery/Makefileindex c60314d..ad54859 100644--- a/src/test/recovery/Makefile+++ b/src/test/recovery/Makefile@@ -10,6 +10,14 @@
#-------------------------------------------------------------------------
EXTRA_INSTALL=contrib/pg_prewarm contrib/pg_stat_statements contrib/test_decoding
+EXTRA_INSTALL += \+ contrib/pg_visibility \+ contrib/amcheck \+ contrib/pgstattuple \+ contrib/btree_gin \+ contrib/pg_surgery \+ contrib/pg_freespacemap \+ contrib/pgrowlocks
subdir = src/test/recovery
top_builddir = ../../..
diff --git a/src/test/recovery/t/001_stream_rep.pl b/src/test/recovery/t/001_stream_rep.plindex 0c72ba0..e441cb2 100644--- a/src/test/recovery/t/001_stream_rep.pl+++ b/src/test/recovery/t/001_stream_rep.pl@@ -45,6 +45,24 @@ $node_standby_2->start;
# Create some content on primary and check its presence in standby nodes
$node_primary->safe_psql('postgres',
"CREATE TABLE tab_int AS SELECT generate_series(1,1002) AS a");
+$node_primary->safe_psql('postgres', "+create extension pg_visibility;+create extension amcheck;+create extension pgstattuple;+create extension btree_gin;+create extension pg_surgery;+create extension pg_prewarm;+create extension pg_freespacemap;+create extension pgrowlocks;++create unlogged sequence useq;+create unlogged table u (c text);+insert into u values ('foo');+create index ubtree on u (c);+create index ugin on u using gin (c);+create index uhash on u using hash (c);+create index ubrin on u using brin (c);+");
# Wait for standbys to catch up
$node_primary->wait_for_replay_catchup($node_standby_1);
@@ -60,6 +78,88 @@ $result =
print "standby 2: $result\n";
is($result, qq(1002), 'check streamed content on standby 2');
+# Call regclass-arg functions on unlogged objects. Function list from:+#+# DO $$+# DECLARE+# extname text;+# BEGIN+# FOR extname in SELECT name from pg_available_extensions LOOP+# EXECUTE format('CREATE EXTENSION IF NOT EXISTS %I CASCADE', extname);+# END LOOP;+# END+# $$;+# select oid::regprocedure from pg_proc+# where proargtypes::oid[] @> array['regclass'::regtype::oid]+# order by oid::regprocedure::text;+#+# Removed pageinspect functions, since the superuser might choose to run them+# in cases we wouldn't expect. Added pgrowlocks(text).+$node_standby_2->psql('postgres', <<'EOSQL', on_error_stop => 0);+\set utable '''u''::regclass'+\set VERBOSITY verbose+SET log_error_verbosity = verbose;+SET log_min_messages = debug1; -- for amcheck+SET client_min_messages = debug1;++SELECT * FROM pgrowlocks(:utable::text);+SELECT brin_desummarize_range('ubrin',1);+SELECT brin_summarize_new_values('ubrin');+SELECT brin_summarize_range('ubrin',1);+SELECT bt_index_check('ubtree');+SELECT bt_index_check('ubtree',true);+SELECT bt_index_parent_check('ubtree');+SELECT bt_index_parent_check('ubtree',true);+SELECT bt_index_parent_check('ubtree',true,true);+SELECT gin_clean_pending_list('ugin');+SELECT heap_force_freeze(:utable,array['(0,1)'::tid]);+SELECT heap_force_kill(:utable,array['(0,1)'::tid]);+SELECT nextval('useq');+SELECT currval('useq');+SELECT pg_check_frozen(:utable);+SELECT pg_check_visible(:utable);+SELECT pg_column_is_updatable(:utable,'1',true);+--SELECT pg_extension_config_dump(:utable,'select 1');+SELECT pg_freespace(:utable);+SELECT pg_freespace(:utable,1);+SELECT pg_get_replica_identity_index(:utable);+SELECT pg_index_column_has_property(:utable,1,'asc');+SELECT pg_indexes_size(:utable);+SELECT pg_index_has_property('ubrin','asc');+--SELECT pg_nextoid(:utable,name,:utable);+SELECT pg_partition_ancestors(:utable);+SELECT pg_partition_root(:utable);+SELECT pg_partition_tree(:utable);+SELECT pg_prewarm(:utable);+SELECT pg_relation_filenode(:utable);+SELECT pg_relation_filepath(:utable);+SELECT pg_relation_is_publishable(:utable);+SELECT pg_relation_is_updatable(:utable,true);+SELECT pg_relation_size(:utable);+SELECT pg_relation_size(:utable,'main');+SELECT pg_relpages(:utable);+SELECT pg_sequence_last_value('useq');+SELECT pgstatginindex('ugin');+SELECT pgstathashindex('uhash');+SELECT pgstatindex('ubtree');+SELECT pgstattuple_approx(:utable);+SELECT pgstattuple(:utable);+SELECT pg_table_size(:utable);+SELECT pg_total_relation_size(:utable);+SELECT pg_truncate_visibility_map(:utable);+SELECT pg_visibility_map(:utable);+SELECT pg_visibility_map(:utable,1);+SELECT pg_visibility_map_summary(:utable);+SELECT pg_visibility(:utable);+SELECT pg_visibility(:utable,1);+SELECT setval('useq',1);+SELECT setval('useq',1,true);+SELECT table_to_xml_and_xmlschema(:utable,true,true,'nsp');+SELECT table_to_xml(:utable,true,true,'nsp');+SELECT table_to_xmlschema(:utable,true,true,'nsp');+SELECT verify_heapam(:utable);+EOSQL+
# Likewise, but for a sequence
$node_primary->safe_psql('postgres',
"CREATE SEQUENCE seq1; SELECT nextval('seq1')");
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Reply to all the recipients using the --to and --cc options:
reply via email
To: pgsql-hackers@postgresql.org
Cc: noah@leadboat.com
Subject: Re: pgstatindex vs. !indisready
In-Reply-To: <20231001195309.a3@google.com>
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
This inbox is served by DDX for PostgreSQL; see mirroring instructions
for how to clone and mirror all data and code used for this inbox