diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 9c6257d..0000000 --- a/.travis.yml +++ /dev/null @@ -1,27 +0,0 @@ -language: cpp -sudo: required -dist: trusty -env: - matrix: - - DIST=precise - - DIST=trusty -before_install: - - sudo apt-get -y install wget software-properties-common - - sudo add-apt-repository -y "deb http://apt.postgresql.org/pub/repos/apt/ trusty-pgdg main" && wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add - - - sudo apt-get update - - sudo apt-get -y --force-yes install debhelper devscripts postgresql-server-dev-all -before_script: - - make clean -script: - - make deb -deploy: - - provider: packagecloud - dist: ubuntu/$DIST - package_glob: build/*.deb - username: heroku - repository: dod - token: - secure: Ts66jfdhEZ0fw3LqXrYG/lwDAsi0ptiyYWGHMR8tSYaR/EB1QVStySG9/IcbJ8NkNEyq/ywykp5f5Naug75nwvYZCfRfKeUeZrllkFy0LzMHtQx2lw+yM6CVs7a/yuFKZeVgZcT2F2ktpwGPNvcY1HP/2d2zeIdTHB/rucYymfAsen0ylt7n1Z41p6WYGnaTYr6e4KgUB2FE4xzB7PZ99IXnbGtSl15wiI5rOw+Kt3KVyRIfr/MdvGtZoDVpthtiorWG4zMDjj7uo8NqIHMUtzE4LeSQukCO7S0GlS8timYCJ5VIBUY1Kr0Me44Rr4ip1vBdZ0PMit08PR9t8/VkKNtmvGRQW17Yw/ULmC5a6ao+LwYVzTkDQVerKDpMJMxvsgpV+sUwZx/PejjlICbWiickXc8vMtRfGogn0+oM0LPx8OIjY9qfud/aad0Xoa1/t4b+bVZAMUS7i3K2ffDN4/6gMww2x3LTekuijBWmm/X+RRlt9B9rrcqlSt0W/3OJCtsVIR0eQ7amGfcpfP2PYf22LSjL/rZo4lglqOjFD+k9zR7DhtbJyYtjabGDoMKETJ69ho1OIs5vXvCuqJ1zxRht3NLStHgymbaCCVgiG5cP4pbUp/QpT+JejOQpELGCl5SR3h1MImjctf1daBQiSxkI1Uv1eVRCXqNeFdrcluc= - skip_cleanup: true -notifications: - email: false diff --git a/Makefile b/Makefile index 44bc23b..7270119 100644 --- a/Makefile +++ b/Makefile @@ -1,15 +1,14 @@ -short_ver = 0.3 +short_ver = 1 long_ver = $(shell (git describe --tags --long '--match=v*' 2>/dev/null || echo $(short_ver)-0-unknown) | cut -c2-) -MODULE_big = amcheck +MODULE_big = amcheck_next OBJS = verify_nbtree.o $(WIN32RES) -EXTENSION = amcheck -DATA = amcheck--0.3.sql -PGFILEDESC = "amcheck - function for verifying relation integrity" +EXTENSION = amcheck_next +DATA = amcheck_next--1.sql +PGFILEDESC = "amcheck_next - functions for verifying relation integrity" DOCS = README.md -REGRESS = install_amcheck extern_sort_bytea \ - extern_sort_collations extern_sort_numeric +REGRESS = install_amcheck_next check_btree PG_CONFIG = pg_config PGXS = $(shell $(PG_CONFIG) --pgxs) @@ -22,4 +21,4 @@ deb: rsync -Ca --exclude=build/* ./ $(DEBUILD_ROOT)/ cd $(DEBUILD_ROOT) && make -f debian/rules orig cd $(DEBUILD_ROOT) && debuild -us -uc -sa - cp -a /tmp/amcheck_* /tmp/postgresql-9.* build/ + cp -a /tmp/amcheck_* /tmp/postgresql-[91]* build/ diff --git a/README.md b/README.md index 19528d5..544f3a4 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # amcheck: Verify the logical consistency of PostgreSQL B-Tree indexes -Current version: 0.3 +Current version: 1.0 (`amcheck_next` extension/SQL version: 1) Author: Peter Geoghegan [``](mailto:pg@bowt.ie) @@ -20,6 +20,14 @@ in production PostgreSQL installations. See "Using amcheck effectively" below for information about the kinds of real-world problems `amcheck` is intended to detect. +### Project background + +`amcheck` is a contrib extension for PostgreSQL 10+. This externally +maintained version of the extension, `amcheck_next`, exists to target earlier +versions of PostgreSQL, and to provide extended verification functionality to +older PostgreSQL versions. It is safe (though generally not useful) to install +`amcheck_next` alongside `contrib/amcheck`. + ### Invariants `amcheck` provides functions that specifically verify various *invariants* in @@ -41,11 +49,6 @@ to guide the scan to a point in the underlying table; see http://www.postgresql.org/docs/current/static/xindex.html for details of operator class support functions. -### Project background - -`amcheck` is a contrib extension for PostgreSQL 10. This externally maintained -version of the extension exists to target earlier versions of PostgreSQL. - ### Bugs Report bugs using the Sat, 07 Oct 2017 09:28:38 -0700 + amcheck (0.3-1) unstable; urgency=low * Tweaks to some diagnostic messages * Detect disagreement between parent/child B-Tree level - -- Peter Geoghegan Fri, 16 June 2017 17:31:41 -0700 + -- Peter Geoghegan Fri, 16 Jun 2017 17:31:41 -0700 amcheck (0.2-1) unstable; urgency=low diff --git a/debian/control b/debian/control index 4a97460..902e4c5 100644 --- a/debian/control +++ b/debian/control @@ -39,3 +39,12 @@ Description: PostgreSQL extension that verifies indexes during a call to these verification functions, no logical inconsistency was detected. This is useful as a general smoke test to detect corruption. +Package: postgresql-10-amcheck +Section: libs +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends}, postgresql-10 +Description: PostgreSQL extension that verifies indexes + This extension verifies the logical consistency of PostgreSQL B-Tree indexes. + The extension consists of SQL-callable functions. When no error is raised + during a call to these verification functions, no logical inconsistency was + detected. This is useful as a general smoke test to detect corruption. diff --git a/debian/pgversions b/debian/pgversions index e01d16e..7466d8e 100644 --- a/debian/pgversions +++ b/debian/pgversions @@ -1,7 +1,6 @@ # Only support versions with robust approach to B-Tree page deletion and # concurrent page splits -# -# PostgreSQL 10 is not supported, if only because its contrib extension has a conflicting extension name. 9.4 9.5 9.6 +10 diff --git a/debian/source/format b/debian/source/format index 163aaf8..d3827e7 100644 --- a/debian/source/format +++ b/debian/source/format @@ -1 +1 @@ -3.0 (quilt) +1.0 diff --git a/expected/check_btree.out b/expected/check_btree.out new file mode 100644 index 0000000..7c93b47 --- /dev/null +++ b/expected/check_btree.out @@ -0,0 +1,85 @@ +-- minimal test, basically just verifying that amcheck +CREATE TABLE bttest_a(id int8); +CREATE TABLE bttest_b(id int8); +INSERT INTO bttest_a SELECT * FROM generate_series(1, 100000); +INSERT INTO bttest_b SELECT * FROM generate_series(100000, 1, -1); +CREATE INDEX bttest_a_idx ON bttest_a USING btree (id); +CREATE INDEX bttest_b_idx ON bttest_b USING btree (id); +CREATE ROLE bttest_role; +-- verify permissions are checked (error due to function not callable) +SET ROLE bttest_role; +SELECT bt_index_check('bttest_a_idx'::regclass); +ERROR: permission denied for function bt_index_check +SELECT bt_index_parent_check('bttest_a_idx'::regclass); +ERROR: permission denied for function bt_index_parent_check +RESET ROLE; +-- we, intentionally, don't check relation permissions - it's useful +-- to run this cluster-wide with a restricted account, and as tested +-- above explicit permission has to be granted for that. +GRANT EXECUTE ON FUNCTION bt_index_check(regclass) TO bttest_role; +GRANT EXECUTE ON FUNCTION bt_index_parent_check(regclass) TO bttest_role; +SET ROLE bttest_role; +SELECT bt_index_check('bttest_a_idx'); + bt_index_check +---------------- + +(1 row) + +SELECT bt_index_parent_check('bttest_a_idx'); + bt_index_parent_check +----------------------- + +(1 row) + +RESET ROLE; +-- verify plain tables are rejected (error) +SELECT bt_index_check('bttest_a'); +ERROR: "bttest_a" is not an index +SELECT bt_index_parent_check('bttest_a'); +ERROR: "bttest_a" is not an index +-- verify non-existing indexes are rejected (error) +SELECT bt_index_check(17); +ERROR: could not open relation with OID 17 +SELECT bt_index_parent_check(17); +ERROR: could not open relation with OID 17 +-- normal check outside of xact +SELECT bt_index_check('bttest_a_idx'); + bt_index_check +---------------- + +(1 row) + +-- more expansive test +SELECT bt_index_parent_check('bttest_b_idx'); + bt_index_parent_check +----------------------- + +(1 row) + +BEGIN; +SELECT bt_index_check('bttest_a_idx'); + bt_index_check +---------------- + +(1 row) + +SELECT bt_index_parent_check('bttest_b_idx'); + bt_index_parent_check +----------------------- + +(1 row) + +-- make sure we don't have any leftover locks +SELECT * FROM pg_locks +WHERE relation = ANY(ARRAY['bttest_a', 'bttest_a_idx', 'bttest_b', 'bttest_b_idx']::regclass[]) + AND pid = pg_backend_pid(); + locktype | database | relation | page | tuple | virtualxid | transactionid | classid | objid | objsubid | virtualtransaction | pid | mode | granted | fastpath +----------+----------+----------+------+-------+------------+---------------+---------+-------+----------+--------------------+-----+------+---------+---------- +(0 rows) + +COMMIT; +-- cleanup +DROP TABLE bttest_a; +DROP TABLE bttest_b; +DROP OWNED BY bttest_role; -- permissions +DROP ROLE bttest_role; diff --git a/expected/extern_sort_bytea.out b/expected/extern_sort_bytea.out deleted file mode 100644 index 54a8f3b..0000000 --- a/expected/extern_sort_bytea.out +++ /dev/null @@ -1,44 +0,0 @@ -CREATE TEMP TABLE bytea_test (i bytea); --- Seed random number generator to make outcome deterministic. -SELECT setseed(0.5); - setseed ---------- - -(1 row) - -INSERT INTO bytea_test SELECT decode(repeat(md5(random()::text), (random() * 100)::int4), 'hex') - FROM generate_series(0, 100000); -SET maintenance_work_mem = '1MB'; -CREATE INDEX idx_bytea ON bytea_test(i); -SELECT bt_index_parent_check('idx_bytea'); - bt_index_parent_check ------------------------ - -(1 row) - -SET maintenance_work_mem = '3MB'; -REINDEX INDEX idx_bytea; -SELECT bt_index_parent_check('idx_bytea'); - bt_index_parent_check ------------------------ - -(1 row) - -SET maintenance_work_mem = '5MB'; -REINDEX INDEX idx_bytea; -SELECT bt_index_parent_check('idx_bytea'); - bt_index_parent_check ------------------------ - -(1 row) - -SET maintenance_work_mem = '20MB'; -REINDEX INDEX idx_bytea; -SELECT bt_index_parent_check('idx_bytea'); - bt_index_parent_check ------------------------ - -(1 row) - --- drop the temporary table -DROP TABLE bytea_test; diff --git a/expected/extern_sort_collations.out b/expected/extern_sort_collations.out deleted file mode 100644 index b7ab20c..0000000 --- a/expected/extern_sort_collations.out +++ /dev/null @@ -1,44 +0,0 @@ --- Perform tests of external sorting collated text. Only test at most 10 --- available collations, to make sure that the tests complete in a reasonable --- amount of time. -DO $x$ -DECLARE - r record; - index_build_mem int4; -BEGIN - FOR r IN SELECT oid, collname FROM pg_collation - WHERE collencoding = (SELECT encoding FROM pg_database WHERE datname = current_database()) - ORDER BY oid LIMIT 10 LOOP - - EXECUTE format($y$CREATE TEMP TABLE text_test_collation (i text COLLATE "%s");$y$, r.collname); - - -- Seed random number generator so that each collation that happens to be - -- available on the system consistently sorts the same strings, using the - -- same maintenance_work_mem setting. In theory, varying these makes the - -- tests more likely to catch problems. - PERFORM setseed(get_byte(decode(md5(r.collname), 'hex'), 5) / 256.0); - -- Don't actually output collation names - -- RAISE NOTICE '%', r.collname; - - -- Make sure MD5 strings contain some space characters, and a doublequote, so - -- multiple "weight levels" are represented. Typically, OS strcoll() - -- implementations follow the conventions of the standard Unicode collation - -- algorithm, and primarily weight alphabetical ordering when comparing - -- strings. - INSERT INTO text_test_collation - SELECT replace(replace(md5(random()::text), '4', ' '), '9', '"') - FROM generate_series(0, 100000); - - -- Set maintenance_work_mem to at least mimimum value, 1MB, and at most 10MB - -- to test external sorting: - index_build_mem := (SELECT greatest((random() * 1024 * 10)::int4, 1024)); - -- Don't actually output pseudo-random maintenance_work_mem: - -- RAISE NOTICE '%', index_build_mem; - EXECUTE 'SET maintenance_work_mem = ' || index_build_mem; - CREATE INDEX idx_text ON text_test_collation(i); - PERFORM bt_index_parent_check('idx_text'); - -- drop the temporary table - DROP TABLE text_test_collation; - END LOOP; -END; -$x$; diff --git a/expected/extern_sort_numeric.out b/expected/extern_sort_numeric.out deleted file mode 100644 index 253f9b3..0000000 --- a/expected/extern_sort_numeric.out +++ /dev/null @@ -1,44 +0,0 @@ -CREATE TEMP TABLE numeric_test (i numeric); --- Seed random number generator to make outcome deterministic. -SELECT setseed(0.5); - setseed ---------- - -(1 row) - -INSERT INTO numeric_test SELECT random() * 100000000 FROM generate_series(0, 5000000); --- special cases -INSERT INTO numeric_test SELECT exp(0.0); -INSERT INTO numeric_test SELECT exp(1.0); -INSERT INTO numeric_test SELECT exp(1.0::numeric(71,70)); -INSERT INTO numeric_test SELECT 0.0 ^ 0.0; -INSERT INTO numeric_test SELECT (-12.34) ^ 0.0; -INSERT INTO numeric_test SELECT 12.34 ^ 0.0; -INSERT INTO numeric_test SELECT 0.0 ^ 12.34; -SET maintenance_work_mem = '1MB'; -CREATE INDEX idx_numeric ON numeric_test(i); -SELECT bt_index_parent_check('idx_numeric'); - bt_index_parent_check ------------------------ - -(1 row) - -SET maintenance_work_mem = '5MB'; -REINDEX INDEX idx_numeric; -SELECT bt_index_parent_check('idx_numeric'); - bt_index_parent_check ------------------------ - -(1 row) - --- Only this final REINDEX requires just one merge pass: -SET maintenance_work_mem = '20MB'; -REINDEX INDEX idx_numeric; -SELECT bt_index_parent_check('idx_numeric'); - bt_index_parent_check ------------------------ - -(1 row) - --- drop the temporary table -DROP TABLE numeric_test; diff --git a/expected/install_amcheck.out b/expected/install_amcheck.out deleted file mode 100644 index 5b3e6d5..0000000 --- a/expected/install_amcheck.out +++ /dev/null @@ -1 +0,0 @@ -CREATE EXTENSION amcheck; diff --git a/expected/install_amcheck_next.out b/expected/install_amcheck_next.out new file mode 100644 index 0000000..22d5f79 --- /dev/null +++ b/expected/install_amcheck_next.out @@ -0,0 +1 @@ +CREATE EXTENSION amcheck_next; diff --git a/sql/check_btree.sql b/sql/check_btree.sql new file mode 100644 index 0000000..449e404 --- /dev/null +++ b/sql/check_btree.sql @@ -0,0 +1,55 @@ +-- minimal test, basically just verifying that amcheck +CREATE TABLE bttest_a(id int8); +CREATE TABLE bttest_b(id int8); + +INSERT INTO bttest_a SELECT * FROM generate_series(1, 100000); +INSERT INTO bttest_b SELECT * FROM generate_series(100000, 1, -1); + +CREATE INDEX bttest_a_idx ON bttest_a USING btree (id); +CREATE INDEX bttest_b_idx ON bttest_b USING btree (id); + +CREATE ROLE bttest_role; + +-- verify permissions are checked (error due to function not callable) +SET ROLE bttest_role; +SELECT bt_index_check('bttest_a_idx'::regclass); +SELECT bt_index_parent_check('bttest_a_idx'::regclass); +RESET ROLE; + +-- we, intentionally, don't check relation permissions - it's useful +-- to run this cluster-wide with a restricted account, and as tested +-- above explicit permission has to be granted for that. +GRANT EXECUTE ON FUNCTION bt_index_check(regclass) TO bttest_role; +GRANT EXECUTE ON FUNCTION bt_index_parent_check(regclass) TO bttest_role; +SET ROLE bttest_role; +SELECT bt_index_check('bttest_a_idx'); +SELECT bt_index_parent_check('bttest_a_idx'); +RESET ROLE; + +-- verify plain tables are rejected (error) +SELECT bt_index_check('bttest_a'); +SELECT bt_index_parent_check('bttest_a'); + +-- verify non-existing indexes are rejected (error) +SELECT bt_index_check(17); +SELECT bt_index_parent_check(17); + +-- normal check outside of xact +SELECT bt_index_check('bttest_a_idx'); +-- more expansive test +SELECT bt_index_parent_check('bttest_b_idx'); + +BEGIN; +SELECT bt_index_check('bttest_a_idx'); +SELECT bt_index_parent_check('bttest_b_idx'); +-- make sure we don't have any leftover locks +SELECT * FROM pg_locks +WHERE relation = ANY(ARRAY['bttest_a', 'bttest_a_idx', 'bttest_b', 'bttest_b_idx']::regclass[]) + AND pid = pg_backend_pid(); +COMMIT; + +-- cleanup +DROP TABLE bttest_a; +DROP TABLE bttest_b; +DROP OWNED BY bttest_role; -- permissions +DROP ROLE bttest_role; diff --git a/sql/extern_sort_bytea.sql b/sql/extern_sort_bytea.sql deleted file mode 100644 index a302c55..0000000 --- a/sql/extern_sort_bytea.sql +++ /dev/null @@ -1,23 +0,0 @@ -CREATE TEMP TABLE bytea_test (i bytea); - --- Seed random number generator to make outcome deterministic. -SELECT setseed(0.5); - -INSERT INTO bytea_test SELECT decode(repeat(md5(random()::text), (random() * 100)::int4), 'hex') - FROM generate_series(0, 100000); - -SET maintenance_work_mem = '1MB'; -CREATE INDEX idx_bytea ON bytea_test(i); -SELECT bt_index_parent_check('idx_bytea'); -SET maintenance_work_mem = '3MB'; -REINDEX INDEX idx_bytea; -SELECT bt_index_parent_check('idx_bytea'); -SET maintenance_work_mem = '5MB'; -REINDEX INDEX idx_bytea; -SELECT bt_index_parent_check('idx_bytea'); -SET maintenance_work_mem = '20MB'; -REINDEX INDEX idx_bytea; -SELECT bt_index_parent_check('idx_bytea'); - --- drop the temporary table -DROP TABLE bytea_test; diff --git a/sql/extern_sort_collations.sql b/sql/extern_sort_collations.sql deleted file mode 100644 index b7ab20c..0000000 --- a/sql/extern_sort_collations.sql +++ /dev/null @@ -1,44 +0,0 @@ --- Perform tests of external sorting collated text. Only test at most 10 --- available collations, to make sure that the tests complete in a reasonable --- amount of time. -DO $x$ -DECLARE - r record; - index_build_mem int4; -BEGIN - FOR r IN SELECT oid, collname FROM pg_collation - WHERE collencoding = (SELECT encoding FROM pg_database WHERE datname = current_database()) - ORDER BY oid LIMIT 10 LOOP - - EXECUTE format($y$CREATE TEMP TABLE text_test_collation (i text COLLATE "%s");$y$, r.collname); - - -- Seed random number generator so that each collation that happens to be - -- available on the system consistently sorts the same strings, using the - -- same maintenance_work_mem setting. In theory, varying these makes the - -- tests more likely to catch problems. - PERFORM setseed(get_byte(decode(md5(r.collname), 'hex'), 5) / 256.0); - -- Don't actually output collation names - -- RAISE NOTICE '%', r.collname; - - -- Make sure MD5 strings contain some space characters, and a doublequote, so - -- multiple "weight levels" are represented. Typically, OS strcoll() - -- implementations follow the conventions of the standard Unicode collation - -- algorithm, and primarily weight alphabetical ordering when comparing - -- strings. - INSERT INTO text_test_collation - SELECT replace(replace(md5(random()::text), '4', ' '), '9', '"') - FROM generate_series(0, 100000); - - -- Set maintenance_work_mem to at least mimimum value, 1MB, and at most 10MB - -- to test external sorting: - index_build_mem := (SELECT greatest((random() * 1024 * 10)::int4, 1024)); - -- Don't actually output pseudo-random maintenance_work_mem: - -- RAISE NOTICE '%', index_build_mem; - EXECUTE 'SET maintenance_work_mem = ' || index_build_mem; - CREATE INDEX idx_text ON text_test_collation(i); - PERFORM bt_index_parent_check('idx_text'); - -- drop the temporary table - DROP TABLE text_test_collation; - END LOOP; -END; -$x$; diff --git a/sql/extern_sort_numeric.sql b/sql/extern_sort_numeric.sql deleted file mode 100644 index 018b87a..0000000 --- a/sql/extern_sort_numeric.sql +++ /dev/null @@ -1,29 +0,0 @@ -CREATE TEMP TABLE numeric_test (i numeric); - --- Seed random number generator to make outcome deterministic. -SELECT setseed(0.5); - -INSERT INTO numeric_test SELECT random() * 100000000 FROM generate_series(0, 5000000); - --- special cases -INSERT INTO numeric_test SELECT exp(0.0); -INSERT INTO numeric_test SELECT exp(1.0); -INSERT INTO numeric_test SELECT exp(1.0::numeric(71,70)); -INSERT INTO numeric_test SELECT 0.0 ^ 0.0; -INSERT INTO numeric_test SELECT (-12.34) ^ 0.0; -INSERT INTO numeric_test SELECT 12.34 ^ 0.0; -INSERT INTO numeric_test SELECT 0.0 ^ 12.34; - -SET maintenance_work_mem = '1MB'; -CREATE INDEX idx_numeric ON numeric_test(i); -SELECT bt_index_parent_check('idx_numeric'); -SET maintenance_work_mem = '5MB'; -REINDEX INDEX idx_numeric; -SELECT bt_index_parent_check('idx_numeric'); --- Only this final REINDEX requires just one merge pass: -SET maintenance_work_mem = '20MB'; -REINDEX INDEX idx_numeric; -SELECT bt_index_parent_check('idx_numeric'); - --- drop the temporary table -DROP TABLE numeric_test; diff --git a/sql/install_amcheck.sql b/sql/install_amcheck.sql deleted file mode 100644 index 5b3e6d5..0000000 --- a/sql/install_amcheck.sql +++ /dev/null @@ -1 +0,0 @@ -CREATE EXTENSION amcheck; diff --git a/sql/install_amcheck_next.sql b/sql/install_amcheck_next.sql new file mode 100644 index 0000000..22d5f79 --- /dev/null +++ b/sql/install_amcheck_next.sql @@ -0,0 +1 @@ +CREATE EXTENSION amcheck_next; diff --git a/verify_nbtree.c b/verify_nbtree.c index dba8159..54287d3 100644 --- a/verify_nbtree.c +++ b/verify_nbtree.c @@ -14,7 +14,7 @@ * Portions Copyright (c) 1994, The Regents of the University of California * * IDENTIFICATION - * contrib/amcheck/verify_nbtree.c + * amcheck_next/verify_nbtree.c * *------------------------------------------------------------------------- */ @@ -91,8 +91,8 @@ typedef struct BtreeLevel bool istruerootlevel; } BtreeLevel; -PG_FUNCTION_INFO_V1(bt_index_check); -PG_FUNCTION_INFO_V1(bt_index_parent_check); +PG_FUNCTION_INFO_V1(bt_index_check_next); +PG_FUNCTION_INFO_V1(bt_index_parent_check_next); static void bt_index_check_internal(Oid indrelid, bool parentcheck); static inline void btree_index_checkable(Relation rel); @@ -120,13 +120,16 @@ static Page palloc_btree_page(BtreeCheckState *state, BlockNumber blocknum); /* * bt_index_check(index regclass) * + * Note that the symbol name is appended with "_next", to avoid symbol clashes + * with contrib/amcheck. + * * Verify integrity of B-Tree index. * * Acquires AccessShareLock on heap & index relations. Does not consider * invariants that exist between parent/child pages. */ Datum -bt_index_check(PG_FUNCTION_ARGS) +bt_index_check_next(PG_FUNCTION_ARGS) { Oid indrelid = PG_GETARG_OID(0); @@ -138,13 +141,16 @@ bt_index_check(PG_FUNCTION_ARGS) /* * bt_index_parent_check(index regclass) * + * Note that the symbol name is appended with "_next", to avoid symbol clashes + * with contrib/amcheck. + * * Verify integrity of B-Tree index. * * Acquires ShareLock on heap & index relations. Verifies that downlinks in * parent pages are valid lower bounds on child pages. */ Datum -bt_index_parent_check(PG_FUNCTION_ARGS) +bt_index_parent_check_next(PG_FUNCTION_ARGS) { Oid indrelid = PG_GETARG_OID(0); @@ -282,6 +288,12 @@ bt_check_every_level(Relation rel, bool readonly) uint32 previouslevel; BtreeLevel current; + /* + * RecentGlobalXmin assertion matches index_getnext_tid(). See note on + * RecentGlobalXmin/B-Tree page deletion. + */ + Assert(TransactionIdIsValid(RecentGlobalXmin)); + /* * Initialize state for entire verification operation */