From b68f938011cef356d6ccb5b86cec4558240601be Mon Sep 17 00:00:00 2001 From: Andrey Borodin Date: Sun, 8 Nov 2026 11:18:25 +0500 Subject: [PATCH v7 3/3] doc: describe indexallkeysmatch verification Document the additional dedicated full heap scan, Bloom-filter memory and false-positive limits, and the lock-dependent treatment of unused heap slots. Describe the unconditional beyond-EOF check separately from the optional reverse-key verification. Author: Andrey Borodin Author: Jakub Wartak Reviewed-by: Zsolt Parragi Discussion: https://postgr.es/m/432626F9-65DF-4F0D-B345-26CFC3E2CFAC@yandex-team.ru --- doc/src/sgml/amcheck.sgml | 81 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 75 insertions(+), 6 deletions(-) diff --git a/doc/src/sgml/amcheck.sgml b/doc/src/sgml/amcheck.sgml index 13a6bb18897..e465ce06efc 100644 --- a/doc/src/sgml/amcheck.sgml +++ b/doc/src/sgml/amcheck.sgml @@ -61,7 +61,7 @@ - bt_index_check(index regclass, heapallindexed boolean, checkunique boolean) returns void + bt_index_check(index regclass, heapallindexed boolean, checkunique boolean, indexallkeysmatch boolean) returns void bt_index_check @@ -118,7 +118,10 @@ ORDER BY c.relpages DESC LIMIT 10; that span child/parent relationships, but will verify the presence of all heap tuples as index tuples within the index when heapallindexed is - true. When checkunique + true. When indexallkeysmatch + is true, it verifies that each index tuple + points to a heap tuple with the same key (the reverse of + heapallindexed). When checkunique is true bt_index_check will check that no more than one among duplicate entries in unique index is visible. When a routine, lightweight test for @@ -127,12 +130,20 @@ ORDER BY c.relpages DESC LIMIT 10; trade-off between thoroughness of verification and limiting the impact on application performance and availability. + + Both B-Tree checking functions report index tuples that point to heap + blocks beyond the end of the table, even when + indexallkeysmatch is false. + This can detect a lost relation segment. The check is skipped if the + table's main relation fork is absent, allowing indexes to be checked + independently of heap verification. + - bt_index_parent_check(index regclass, heapallindexed boolean, rootdescend boolean, checkunique boolean) returns void + bt_index_parent_check(index regclass, heapallindexed boolean, rootdescend boolean, checkunique boolean, indexallkeysmatch boolean) returns void bt_index_parent_check @@ -145,7 +156,9 @@ ORDER BY c.relpages DESC LIMIT 10; Optionally, when the heapallindexed argument is true, the function verifies the presence of all heap tuples that should be found within the - index. When checkunique + index. When indexallkeysmatch is + true, it verifies that each index tuple + points to a heap tuple with the same key. When checkunique is true bt_index_parent_check will check that no more than one among duplicate entries in unique index is visible. When the optional rootdescend @@ -413,6 +426,59 @@ SET client_min_messages = DEBUG1; single absent or malformed tuple has a new opportunity to be detected with each new verification attempt. + + When both heapallindexed and + indexallkeysmatch are enabled, two Bloom + filters are allocated, each up to maintenance_work_mem. + + + + + + Optional <parameter>indexallkeysmatch</parameter> Verification + + When the indexallkeysmatch argument to B-Tree + verification functions is true, an additional + phase verifies that each index tuple points to a heap tuple with the + same key. This is the reverse of heapallindexed: + heapallindexed checks that every heap tuple is + in the index, while indexallkeysmatch checks + that every index tuple points to a matching heap tuple. + + + The implementation uses a Bloom filter to amortize random heap + lookups. An additional dedicated full sequential heap scan first + fingerprints all visible (key, tid) pairs. This scan is required even + when heapallindexed is also enabled, and can be + expensive for large tables. During the index scan, each leaf tuple is probed + against this filter. Only when the filter says "not present" does + an actual heap fetch and key comparison occur. Corruption is + reported when the heap tuple's key (as computed by + FormIndexDatum) differs from the index tuple's + key. + Additionally, bt_index_parent_check + reports index tuples pointing to unused heap slots; under the weaker + lock taken by bt_index_check such slots cannot + be reliably distinguished from tuples concurrently removed by + VACUUM, so they are skipped. + + + Like heapallindexed, this check requires an + MVCC snapshot to obtain a consistent view of the heap and index. + The heap lookup follows HOT chains the same way a + regular index scan does. Heap tuple versions not visible to the + snapshot are not compared. + + + The summarizing structure is bound in size by + maintenance_work_mem, using the same sizing + approach as heapallindexed. In order to ensure + that there is no more than a 2% probability of failure to detect an + inconsistency for each index tuple that should match a heap tuple, + approximately 2 bytes of memory are needed per tuple. As less memory + is made available per tuple, the probability of missing an + inconsistency slowly increases. + @@ -457,12 +523,15 @@ SET client_min_messages = DEBUG1; Structural inconsistencies between indexes and the heap relations - that are indexed (when heapallindexed - verification is performed). + that are indexed (when heapallindexed or + indexallkeysmatch verification is performed). There is no cross-checking of indexes against their heap relation during normal operation. Symptoms of heap corruption can be subtle. + indexallkeysmatch detects cases where an index + tuple stores a different key than the heap tuple it points to, or + points to a non-existent heap slot. -- 2.50.1 (Apple Git-155)