v1-0001-WIP-patch-to-support-amcheck-of-sequences.patch.WIP
application/octet-stream
Filename: v1-0001-WIP-patch-to-support-amcheck-of-sequences.patch.WIP
Type: application/octet-stream
Part: 0
Message:
Re: verify_heapam for sequences?
From 6f45093233d79bf719b3c6d1df1d2eae971eead2 Mon Sep 17 00:00:00 2001
From: Mark Dilger <mark.dilger@enterprisedb.com>
Date: Thu, 26 Aug 2021 11:52:50 -0700
Subject: [PATCH v1] WIP patch to support amcheck of sequences
---
contrib/amcheck/expected/check_heap.out | 6 +-
contrib/amcheck/t/001_verify_heapam.pl | 102 +++++++++++++++++++++++-
contrib/amcheck/verify_heapam.c | 10 ++-
3 files changed, 113 insertions(+), 5 deletions(-)
diff --git a/contrib/amcheck/expected/check_heap.out b/contrib/amcheck/expected/check_heap.out
index ad3086d2aa..c010361025 100644
--- a/contrib/amcheck/expected/check_heap.out
+++ b/contrib/amcheck/expected/check_heap.out
@@ -180,8 +180,10 @@ CREATE SEQUENCE test_sequence;
SELECT * FROM verify_heapam('test_sequence',
startblock := NULL,
endblock := NULL);
-ERROR: cannot check relation "test_sequence"
-DETAIL: This operation is not supported for sequences.
+ blkno | offnum | attnum | msg
+-------+--------+--------+-----
+(0 rows)
+
-- Check that foreign tables are rejected
CREATE FOREIGN DATA WRAPPER dummy;
CREATE SERVER dummy_server FOREIGN DATA WRAPPER dummy;
diff --git a/contrib/amcheck/t/001_verify_heapam.pl b/contrib/amcheck/t/001_verify_heapam.pl
index 4f720a7ed0..174a132264 100644
--- a/contrib/amcheck/t/001_verify_heapam.pl
+++ b/contrib/amcheck/t/001_verify_heapam.pl
@@ -8,7 +8,7 @@ use PostgresNode;
use TestLib;
use Fcntl qw(:seek);
-use Test::More tests => 80;
+use Test::More tests => 133;
my ($node, $result);
@@ -21,6 +21,30 @@ $node->append_conf('postgresql.conf', 'autovacuum=off');
$node->start;
$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+#
+# Check a sequence with no corruption
+#
+fresh_test_sequence('test_seq');
+check_all_options_uncorrupted('test_seq', 'sequence');
+
+#
+# Check a corrupt sequence
+#
+corrupt_sequence_relfile('test_seq');
+detects_sequence_corruption("verify_heapam('test_seq')", "corrupted sequence");
+detects_sequence_corruption(
+ "verify_heapam('test_seq', skip := 'all-visible')",
+ "corrupted sequence skipping all-visible");
+detects_sequence_corruption(
+ "verify_heapam('test_seq', skip := 'all-frozen')",
+ "corrupted sequence skipping all-frozen");
+detects_sequence_corruption(
+ "verify_heapam('test_seq', check_toast := false)",
+ "corrupted sequence skipping toast");
+detects_sequence_corruption(
+ "verify_heapam('test_seq', startblock := 0, endblock := 0)",
+ "corrupted sequence checking only block zero");
+
#
# Check a table with data loaded but no corruption, freezing, etc.
#
@@ -110,6 +134,71 @@ sub fresh_test_table
));
}
+# (Re)create and populate a test sequence of the given name
+sub fresh_test_sequence
+{
+ my ($seqname) = @_;
+
+ return $node->safe_psql(
+ 'postgres', qq(
+ DROP SEQUENCE IF EXISTS $seqname CASCADE;
+ CREATE SEQUENCE $seqname
+ INCREMENT BY 13
+ MINVALUE 17
+ START WITH 23;
+ BEGIN;
+ SELECT nextval('$seqname');
+ COMMIT;
+ ALTER SEQUENCE $seqname RESTART;
+ SELECT setval('$seqname', 40);
+ SELECT nextval('$seqname');
+ SELECT nextval('$seqname');
+ SELECT nextval('$seqname');
+ ROLLBACK;
+ BEGIN;
+ SELECT setval('$seqname', 35);
+ SELECT nextval('$seqname');
+ COMMIT;
+ ));
+}
+
+# Stops the test node, corrupts the first page of the named sequence, and
+# restarts the node.
+sub corrupt_sequence_relfile
+{
+ my ($relname) = @_;
+ my $relpath = relation_filepath($relname);
+
+ $node->stop;
+
+ my $fh;
+ open($fh, '+<', $relpath)
+ or BAIL_OUT("open failed: $!");
+ binmode $fh;
+
+ my $size = (stat($fh))[7];
+
+ # Loop over 2k chunks, to be compatible with all supported page sizes
+ for (my $start = 0; $start < $size; $start += 2048)
+ {
+ # Don't touch the page header
+ seek($fh, $start + 32, SEEK_SET)
+ or BAIL_OUT("seek failed: $!");
+
+ # Corrupt the remainder of the 2k chunk
+ syswrite(
+ $fh,
+ pack("L*", (0xAAA15550, 0xAAA0D550, 0x00010000,
+ 0x00008000, 0x0000800F, 0x001e8000) x 84)
+ ) or BAIL_OUT("syswrite failed: $!");
+ }
+
+ close($fh)
+ or BAIL_OUT("close failed: $!");
+
+ $node->start;
+}
+
# Stops the test node, corrupts the first page of the named relation, and
# restarts the node.
sub corrupt_first_page
@@ -141,6 +230,17 @@ sub corrupt_first_page
$node->start;
}
+sub detects_sequence_corruption
+{
+ my ($function, $testname) = @_;
+
+ detects_corruption(
+ $function,
+ $testname,
+ qr/\w+/ # accept any corruption message
+ );
+}
+
sub detects_heap_corruption
{
my ($function, $testname) = @_;
diff --git a/contrib/amcheck/verify_heapam.c b/contrib/amcheck/verify_heapam.c
index 226271923a..85832183e6 100644
--- a/contrib/amcheck/verify_heapam.c
+++ b/contrib/amcheck/verify_heapam.c
@@ -305,14 +305,20 @@ verify_heapam(PG_FUNCTION_ARGS)
*/
if (ctx.rel->rd_rel->relkind != RELKIND_RELATION &&
ctx.rel->rd_rel->relkind != RELKIND_MATVIEW &&
- ctx.rel->rd_rel->relkind != RELKIND_TOASTVALUE)
+ ctx.rel->rd_rel->relkind != RELKIND_TOASTVALUE &&
+ ctx.rel->rd_rel->relkind != RELKIND_SEQUENCE)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("cannot check relation \"%s\"",
RelationGetRelationName(ctx.rel)),
errdetail_relkind_not_supported(ctx.rel->rd_rel->relkind)));
- if (ctx.rel->rd_rel->relam != HEAP_TABLE_AM_OID)
+ /*
+ * Sequences always use heap AM, but they don't show that in the catalogs.
+ * Other relkinds might be using a different AM, so check.
+ */
+ if (ctx.rel->rd_rel->relkind != RELKIND_SEQUENCE &&
+ ctx.rel->rd_rel->relam != HEAP_TABLE_AM_OID)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("only heap AM is supported")));
--
2.21.1 (Apple Git-122.3)