1
0
mirror of https://github.com/postgres/postgres.git synced 2025-12-10 14:22:35 +03:00
Files
postgres/contrib/amcheck/t/002_cic.pl
Álvaro Herrera 6bd469d26a amcheck: Fix snapshot usage in bt_index_parent_check
We were using SnapshotAny to do some index checks, but that's wrong and
causes spurious errors when used on indexes created by CREATE INDEX
CONCURRENTLY.  Fix it to use an MVCC snapshot, and add a test for it.

This problem came in with commit 5ae2087202, which introduced
uniqueness check.  Backpatch to 17.

Author: Mihail Nikalayeu <mihailnikalayeu@gmail.com>
Reviewed-by: Andrey Borodin <x4mmm@yandex-team.ru>
Backpatch-through: 17
Discussion: https://postgr.es/m/CANtu0ojmVd27fEhfpST7RG2KZvwkX=dMyKUqg0KM87FkOSdz8Q@mail.gmail.com
2025-12-04 18:12:08 +01:00

92 lines
2.7 KiB
Perl

# Copyright (c) 2021-2025, PostgreSQL Global Development Group
# Test CREATE INDEX CONCURRENTLY with concurrent modifications
use strict;
use warnings FATAL => 'all';
use PostgreSQL::Test::Cluster;
use PostgreSQL::Test::Utils;
use Test::More;
my $node;
#
# Test set-up
#
$node = PostgreSQL::Test::Cluster->new('CIC_test');
$node->init;
$node->append_conf('postgresql.conf',
'lock_timeout = ' . (1000 * $PostgreSQL::Test::Utils::timeout_default));
$node->start;
$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
$node->safe_psql('postgres', q(CREATE TABLE tbl(i int, j jsonb)));
$node->safe_psql('postgres', q(CREATE INDEX idx ON tbl(i)));
$node->safe_psql('postgres', q(CREATE INDEX ginidx ON tbl USING gin(j)));
#
# Stress CIC with pgbench.
#
# pgbench might try to launch more than one instance of the CIC
# transaction concurrently. That would deadlock, so use an advisory
# lock to ensure only one CIC runs at a time.
#
$node->pgbench(
'--no-vacuum --client=5 --transactions=100',
0,
[qr{actually processed}],
[qr{^$}],
'concurrent INSERTs and CIC',
{
'002_pgbench_concurrent_transaction' => q(
BEGIN;
INSERT INTO tbl VALUES(0, '{"a":[["b",{"x":1}],["b",{"x":2}]],"c":3}');
COMMIT;
),
'002_pgbench_concurrent_transaction_savepoints' => q(
BEGIN;
SAVEPOINT s1;
INSERT INTO tbl VALUES(0, '[[14,2,3]]');
COMMIT;
),
'002_pgbench_concurrent_cic' => q(
SELECT pg_try_advisory_lock(42)::integer AS gotlock \gset
\if :gotlock
DROP INDEX CONCURRENTLY idx;
CREATE INDEX CONCURRENTLY idx ON tbl(i);
DROP INDEX CONCURRENTLY ginidx;
CREATE INDEX CONCURRENTLY ginidx ON tbl USING gin(j);
SELECT bt_index_check('idx',true);
SELECT gin_index_check('ginidx');
SELECT pg_advisory_unlock(42);
\endif
)
});
# Test bt_index_parent_check() with indexes created with
# CREATE INDEX CONCURRENTLY.
$node->safe_psql('postgres', q(CREATE TABLE quebec(i int primary key)));
# Insert two rows into index
$node->safe_psql('postgres',
q(INSERT INTO quebec SELECT i FROM generate_series(1, 2) s(i);));
# start background transaction
my $in_progress_h = $node->background_psql('postgres');
$in_progress_h->query_safe(q(BEGIN; SELECT pg_current_xact_id();));
# delete one row from table, while background transaction is in progress
$node->safe_psql('postgres', q(DELETE FROM quebec WHERE i = 1;));
# create index concurrently, which will skip the deleted row
$node->safe_psql('postgres', q(CREATE INDEX CONCURRENTLY oscar ON quebec(i);));
# check index using bt_index_parent_check
my $result = $node->psql('postgres',
q(SELECT bt_index_parent_check('oscar', heapallindexed => true)));
is($result, '0', 'bt_index_parent_check for CIC after removed row');
$in_progress_h->quit;
$node->stop;
done_testing();