2021-10-23 18:36:38 -07:00
|
|
|
|
2025-01-01 11:21:55 -05:00
|
|
|
# Copyright (c) 2021-2025, PostgreSQL Global Development Group
|
2021-10-23 18:36:38 -07:00
|
|
|
|
|
|
|
# Test CREATE INDEX CONCURRENTLY with concurrent prepared-xact modifications
|
|
|
|
use strict;
|
2023-12-29 18:01:53 +01:00
|
|
|
use warnings FATAL => 'all';
|
2021-10-23 18:36:38 -07:00
|
|
|
|
2021-10-24 10:28:19 -04:00
|
|
|
use PostgreSQL::Test::Cluster;
|
|
|
|
use PostgreSQL::Test::Utils;
|
2021-10-23 18:36:38 -07:00
|
|
|
|
2022-02-11 20:54:44 +01:00
|
|
|
use Test::More;
|
2021-10-23 18:36:38 -07:00
|
|
|
|
2022-02-09 18:16:59 -08:00
|
|
|
Test::More->builder->todo_start('filesystem bug')
|
|
|
|
if PostgreSQL::Test::Utils::has_wal_read_bug;
|
2022-01-26 18:06:19 -08:00
|
|
|
|
2021-10-23 18:36:38 -07:00
|
|
|
my ($node, $result);
|
|
|
|
|
|
|
|
#
|
|
|
|
# Test set-up
|
|
|
|
#
|
2021-10-24 10:28:19 -04:00
|
|
|
$node = PostgreSQL::Test::Cluster->new('CIC_2PC_test');
|
2021-10-23 18:36:38 -07:00
|
|
|
$node->init;
|
|
|
|
$node->append_conf('postgresql.conf', 'max_prepared_transactions = 10');
|
2022-03-04 18:53:13 -08:00
|
|
|
$node->append_conf('postgresql.conf',
|
|
|
|
'lock_timeout = ' . (1000 * $PostgreSQL::Test::Utils::timeout_default));
|
2021-10-23 18:36:38 -07:00
|
|
|
$node->start;
|
|
|
|
$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
|
2025-03-29 16:46:49 +01:00
|
|
|
$node->safe_psql('postgres', q(CREATE TABLE tbl(i int, j jsonb)));
|
2021-10-23 18:36:38 -07:00
|
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
# Run 3 overlapping 2PC transactions with CIC
|
|
|
|
#
|
|
|
|
# We have two concurrent background psql processes: $main_h for INSERTs and
|
|
|
|
# $cic_h for CIC. Also, we use non-background psql for some COMMIT PREPARED
|
|
|
|
# statements.
|
|
|
|
#
|
|
|
|
|
2023-04-07 22:14:20 +02:00
|
|
|
my $main_h = $node->background_psql('postgres');
|
|
|
|
|
2023-05-19 17:24:48 -04:00
|
|
|
$main_h->query_safe(
|
|
|
|
q(
|
2021-10-23 18:36:38 -07:00
|
|
|
BEGIN;
|
2025-03-29 16:46:49 +01:00
|
|
|
INSERT INTO tbl VALUES(0, '[[14,2,3]]');
|
2023-04-07 22:14:20 +02:00
|
|
|
));
|
|
|
|
|
|
|
|
my $cic_h = $node->background_psql('postgres');
|
|
|
|
|
2023-05-19 17:24:48 -04:00
|
|
|
$cic_h->query_until(
|
|
|
|
qr/start/, q(
|
2021-10-23 18:36:38 -07:00
|
|
|
\echo start
|
|
|
|
CREATE INDEX CONCURRENTLY idx ON tbl(i);
|
2025-03-29 16:46:49 +01:00
|
|
|
CREATE INDEX CONCURRENTLY ginidx ON tbl USING gin(j);
|
2023-04-07 22:14:20 +02:00
|
|
|
));
|
2021-10-23 18:36:38 -07:00
|
|
|
|
2023-05-19 17:24:48 -04:00
|
|
|
$main_h->query_safe(
|
|
|
|
q(
|
2021-10-23 18:36:38 -07:00
|
|
|
PREPARE TRANSACTION 'a';
|
2023-04-07 22:14:20 +02:00
|
|
|
));
|
2021-10-23 18:36:38 -07:00
|
|
|
|
2023-05-19 17:24:48 -04:00
|
|
|
$main_h->query_safe(
|
|
|
|
q(
|
2021-10-23 18:36:38 -07:00
|
|
|
BEGIN;
|
2025-03-29 16:46:49 +01:00
|
|
|
INSERT INTO tbl VALUES(0, '[[14,2,3]]');
|
2023-04-07 22:14:20 +02:00
|
|
|
));
|
2021-10-23 18:36:38 -07:00
|
|
|
|
|
|
|
$node->safe_psql('postgres', q(COMMIT PREPARED 'a';));
|
|
|
|
|
2023-05-19 17:24:48 -04:00
|
|
|
$main_h->query_safe(
|
|
|
|
q(
|
2021-10-23 18:36:38 -07:00
|
|
|
PREPARE TRANSACTION 'b';
|
|
|
|
BEGIN;
|
2025-03-29 16:46:49 +01:00
|
|
|
INSERT INTO tbl VALUES(0, '"mary had a little lamb"');
|
2023-04-07 22:14:20 +02:00
|
|
|
));
|
2021-10-23 18:36:38 -07:00
|
|
|
|
|
|
|
$node->safe_psql('postgres', q(COMMIT PREPARED 'b';));
|
|
|
|
|
2023-05-19 17:24:48 -04:00
|
|
|
$main_h->query_safe(
|
|
|
|
q(
|
2021-10-23 18:36:38 -07:00
|
|
|
PREPARE TRANSACTION 'c';
|
|
|
|
COMMIT PREPARED 'c';
|
2023-04-07 22:14:20 +02:00
|
|
|
));
|
2021-10-23 18:36:38 -07:00
|
|
|
|
2023-04-07 22:14:20 +02:00
|
|
|
$main_h->quit;
|
|
|
|
$cic_h->quit;
|
2021-10-23 18:36:38 -07:00
|
|
|
|
|
|
|
$result = $node->psql('postgres', q(SELECT bt_index_check('idx',true)));
|
|
|
|
is($result, '0', 'bt_index_check after overlapping 2PC');
|
|
|
|
|
2025-03-29 16:46:49 +01:00
|
|
|
$result = $node->psql('postgres', q(SELECT gin_index_check('ginidx')));
|
|
|
|
is($result, '0', 'gin_index_check after overlapping 2PC');
|
|
|
|
|
2021-10-23 18:36:38 -07:00
|
|
|
|
|
|
|
#
|
|
|
|
# Server restart shall not change whether prepared xact blocks CIC
|
|
|
|
#
|
|
|
|
|
|
|
|
$node->safe_psql(
|
|
|
|
'postgres', q(
|
|
|
|
BEGIN;
|
2025-03-29 16:46:49 +01:00
|
|
|
INSERT INTO tbl VALUES(0, '{"a":[["b",{"x":1}],["b",{"x":2}]],"c":3}');
|
2021-10-23 18:36:38 -07:00
|
|
|
PREPARE TRANSACTION 'spans_restart';
|
|
|
|
BEGIN;
|
|
|
|
CREATE TABLE unused ();
|
|
|
|
PREPARE TRANSACTION 'persists_forever';
|
|
|
|
));
|
|
|
|
$node->restart;
|
|
|
|
|
2023-04-07 22:14:20 +02:00
|
|
|
my $reindex_h = $node->background_psql('postgres');
|
2023-05-19 17:24:48 -04:00
|
|
|
$reindex_h->query_until(
|
|
|
|
qr/start/, q(
|
2021-10-23 18:36:38 -07:00
|
|
|
\echo start
|
|
|
|
DROP INDEX CONCURRENTLY idx;
|
|
|
|
CREATE INDEX CONCURRENTLY idx ON tbl(i);
|
2025-03-29 16:46:49 +01:00
|
|
|
DROP INDEX CONCURRENTLY ginidx;
|
|
|
|
CREATE INDEX CONCURRENTLY ginidx ON tbl USING gin(j);
|
2023-04-07 22:14:20 +02:00
|
|
|
));
|
2021-10-23 18:36:38 -07:00
|
|
|
|
|
|
|
$node->safe_psql('postgres', "COMMIT PREPARED 'spans_restart'");
|
2023-04-07 22:14:20 +02:00
|
|
|
$reindex_h->quit;
|
2021-10-23 18:36:38 -07:00
|
|
|
$result = $node->psql('postgres', q(SELECT bt_index_check('idx',true)));
|
|
|
|
is($result, '0', 'bt_index_check after 2PC and restart');
|
2025-03-29 16:46:49 +01:00
|
|
|
$result = $node->psql('postgres', q(SELECT gin_index_check('ginidx')));
|
|
|
|
is($result, '0', 'gin_index_check after 2PC and restart');
|
2021-10-23 18:36:38 -07:00
|
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
# Stress CIC+2PC with pgbench
|
|
|
|
#
|
2021-10-28 11:45:14 -04:00
|
|
|
# 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.
|
2021-10-23 18:36:38 -07:00
|
|
|
|
|
|
|
# Fix broken index first
|
|
|
|
$node->safe_psql('postgres', q(REINDEX TABLE tbl;));
|
|
|
|
|
|
|
|
# Run pgbench.
|
|
|
|
$node->pgbench(
|
|
|
|
'--no-vacuum --client=5 --transactions=100',
|
|
|
|
0,
|
|
|
|
[qr{actually processed}],
|
|
|
|
[qr{^$}],
|
2021-10-28 11:45:14 -04:00
|
|
|
'concurrent INSERTs w/ 2PC and CIC',
|
2021-10-23 18:36:38 -07:00
|
|
|
{
|
2021-10-28 11:45:14 -04:00
|
|
|
'003_pgbench_concurrent_2pc' => q(
|
2021-10-23 18:36:38 -07:00
|
|
|
BEGIN;
|
2025-03-29 16:46:49 +01:00
|
|
|
INSERT INTO tbl VALUES(0,'null');
|
2021-10-23 18:36:38 -07:00
|
|
|
PREPARE TRANSACTION 'c:client_id';
|
|
|
|
COMMIT PREPARED 'c:client_id';
|
|
|
|
),
|
2021-10-28 11:45:14 -04:00
|
|
|
'003_pgbench_concurrent_2pc_savepoint' => q(
|
2021-10-23 18:36:38 -07:00
|
|
|
BEGIN;
|
|
|
|
SAVEPOINT s1;
|
2025-03-29 16:46:49 +01:00
|
|
|
INSERT INTO tbl VALUES(0,'[false, "jnvaba", -76, 7, {"_": [1]}, 9]');
|
2021-10-23 18:36:38 -07:00
|
|
|
PREPARE TRANSACTION 'c:client_id';
|
|
|
|
COMMIT PREPARED 'c:client_id';
|
2021-10-28 11:45:14 -04:00
|
|
|
),
|
|
|
|
'003_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);
|
|
|
|
SELECT bt_index_check('idx',true);
|
|
|
|
SELECT pg_advisory_unlock(42);
|
|
|
|
\endif
|
|
|
|
),
|
|
|
|
'004_pgbench_concurrent_ric' => q(
|
|
|
|
SELECT pg_try_advisory_lock(42)::integer AS gotlock \gset
|
|
|
|
\if :gotlock
|
|
|
|
REINDEX INDEX CONCURRENTLY idx;
|
|
|
|
SELECT bt_index_check('idx',true);
|
|
|
|
SELECT pg_advisory_unlock(42);
|
|
|
|
\endif
|
2025-03-29 16:46:49 +01:00
|
|
|
),
|
|
|
|
'005_pgbench_concurrent_cic' => q(
|
|
|
|
SELECT pg_try_advisory_lock(42)::integer AS gotginlock \gset
|
|
|
|
\if :gotginlock
|
|
|
|
DROP INDEX CONCURRENTLY ginidx;
|
|
|
|
CREATE INDEX CONCURRENTLY ginidx ON tbl USING gin(j);
|
|
|
|
SELECT gin_index_check('ginidx');
|
|
|
|
SELECT pg_advisory_unlock(42);
|
|
|
|
\endif
|
|
|
|
),
|
|
|
|
'006_pgbench_concurrent_ric' => q(
|
|
|
|
SELECT pg_try_advisory_lock(42)::integer AS gotginlock \gset
|
|
|
|
\if :gotginlock
|
|
|
|
REINDEX INDEX CONCURRENTLY ginidx;
|
|
|
|
SELECT gin_index_check('ginidx');
|
|
|
|
SELECT pg_advisory_unlock(42);
|
|
|
|
\endif
|
2021-10-23 18:36:38 -07:00
|
|
|
)
|
2025-03-29 16:46:49 +01:00
|
|
|
|
2021-10-23 18:36:38 -07:00
|
|
|
});
|
|
|
|
|
|
|
|
$node->stop;
|
|
|
|
done_testing();
|