agora inbox for [email protected]
help / color / mirror / Atom feed7.1 vs. 7.2 on AIX 5L
966+ messages / 5 participants
[nested] [flat]
* 7.1 vs. 7.2 on AIX 5L
@ 2002-01-09 01:35 Tatsuo Ishii <[email protected]>
0 siblings, 2 replies; 966+ messages in thread
From: Tatsuo Ishii @ 2002-01-09 01:35 UTC (permalink / raw)
To: pgsql-hackers
Hi,
I have made a new version of pgbench which allows not to update
branches and tellers tables, which should significantly reduce the
contentions. (See attached patches against current. Note that the
paches also includes changes removing CHECKPOINT command while
running in initialization mode (pgbench -i)). With the patches you
could specify -N option not to update branches and tellers tables.
With the new pgbench, I ran a test with current and 7.1 and saw
not-so-small differences. Any idea to get better performance on 7.2
and AIX 5L combo?
7.2 with lwlock.patch rev.2
7.1.3
AIX 5L 4way with 4GB RAM
testing script is same as my previous postings (except -N for pgbench,
of course).
Index: pgbench/README.pgbench
===================================================================
RCS file: /cvsroot/pgsql/contrib/pgbench/README.pgbench,v
retrieving revision 1.4
diff -c -r1.4 README.pgbench
*** pgbench/README.pgbench 2001/10/24 08:07:19 1.4
--- pgbench/README.pgbench 2002/01/09 01:31:26
***************
*** 122,127 ****
--- 122,130 ----
-S
Perform select only transactions instead of TPC-B.
+ -N
+ Skip updation of "branches" and "tellers" table. This
+ would result in lower contention of updates.
-C
Establish connection for each transaction, rather than
doing it just once at begining of pgbench in the normal
Index: pgbench/pgbench.c
===================================================================
RCS file: /cvsroot/pgsql/contrib/pgbench/pgbench.c,v
retrieving revision 1.13
diff -c -r1.13 pgbench.c
*** pgbench/pgbench.c 2001/11/05 17:46:23 1.13
--- pgbench/pgbench.c 2002/01/09 01:31:26
***************
*** 4,10 ****
* pgbench: a simple TPC-B like benchmark program for PostgreSQL
* written by Tatsuo Ishii
*
! * Copyright (c) 2000 Tatsuo Ishii
*
* Permission to use, copy, modify, and distribute this software and
* its documentation for any purpose and without fee is hereby
--- 4,10 ----
* pgbench: a simple TPC-B like benchmark program for PostgreSQL
* written by Tatsuo Ishii
*
! * Copyright (c) 2000-2002 Tatsuo Ishii
*
* Permission to use, copy, modify, and distribute this software and
* its documentation for any purpose and without fee is hereby
***************
*** 95,101 ****
static void
usage()
{
! fprintf(stderr, "usage: pgbench [-h hostname][-p port][-c nclients][-t ntransactions][-s scaling_factor][-n][-C][-v][-S][-U login][-P password][-d][dbname]\n");
fprintf(stderr, "(initialize mode): pgbench -i [-h hostname][-p port][-s scaling_factor][-U login][-P password][-d][dbname]\n");
}
--- 95,101 ----
static void
usage()
{
! fprintf(stderr, "usage: pgbench [-h hostname][-p port][-c nclients][-t ntransactions][-s scaling_factor][-n][-C][-v][-S][-N][-U login][-P password][-d][dbname]\n");
fprintf(stderr, "(initialize mode): pgbench -i [-h hostname][-p port][-s scaling_factor][-U login][-P password][-d][dbname]\n");
}
***************
*** 168,174 ****
/* process a transaction */
static void
! doOne(CState * state, int n, int debug)
{
char sql[256];
PGresult *res;
--- 168,174 ----
/* process a transaction */
static void
! doOne(CState * state, int n, int debug, int ttype)
{
char sql[256];
PGresult *res;
***************
*** 295,306 ****
sprintf(sql, "select abalance from accounts where aid = %d", st->aid);
break;
case 3:
! sprintf(sql, "update tellers set tbalance = tbalance + %d where tid = %d\n",
! st->delta, st->tid);
! break;
case 4:
! sprintf(sql, "update branches set bbalance = bbalance + %d where bid = %d", st->delta, st->bid);
! break;
case 5:
sprintf(sql, "insert into history(tid,bid,aid,delta,mtime) values(%d,%d,%d,%d,'now')",
st->tid, st->bid, st->aid, st->delta);
--- 295,312 ----
sprintf(sql, "select abalance from accounts where aid = %d", st->aid);
break;
case 3:
! if (ttype == 0)
! {
! sprintf(sql, "update tellers set tbalance = tbalance + %d where tid = %d\n",
! st->delta, st->tid);
! break;
! }
case 4:
! if (ttype == 0)
! {
! sprintf(sql, "update branches set bbalance = bbalance + %d where bid = %d", st->delta, st->bid);
! break;
! }
case 5:
sprintf(sql, "insert into history(tid,bid,aid,delta,mtime) values(%d,%d,%d,%d,'now')",
st->tid, st->bid, st->aid, st->delta);
***************
*** 549,554 ****
--- 555,561 ----
exit(1);
}
+ #ifdef NOT_USED
/*
* do a checkpoint to purge the old WAL logs
*/
***************
*** 558,563 ****
--- 565,571 ----
fprintf(stderr, "%s", PQerrorMessage(con));
exit(1);
}
+ #endif /* NOT_USED */
}
}
***************
*** 585,590 ****
--- 593,599 ----
t2;
int i;
int normal_xacts = 0;
+ char *s;
for (i = 0; i < nclients; i++)
normal_xacts += state[i].cnt;
***************
*** 594,601 ****
t2 = (tv3->tv_sec - tv2->tv_sec) * 1000000.0 + (tv3->tv_usec - tv2->tv_usec);
t2 = normal_xacts * 1000000.0 / t2;
! printf("transaction type: %s\n", ttype == 0 ? "TPC-B (sort of)" : "SELECT only");
printf("scaling factor: %d\n", tps);
printf("number of clients: %d\n", nclients);
printf("number of transactions per client: %d\n", nxacts);
--- 603,617 ----
t2 = (tv3->tv_sec - tv2->tv_sec) * 1000000.0 + (tv3->tv_usec - tv2->tv_usec);
t2 = normal_xacts * 1000000.0 / t2;
+
+ if (ttype == 0)
+ s = "TPC-B (sort of)";
+ else if (ttype == 2)
+ s = "Update only accounts";
+ else
+ s = "SELECT only";
! printf("transaction type: %s\n", s);
printf("scaling factor: %d\n", tps);
printf("number of clients: %d\n", nclients);
printf("number of transactions per client: %d\n", nxacts);
***************
*** 619,625 ****
int is_full_vacuum = 0; /* do full vacuum before testing? */
int debug = 0; /* debug flag */
int ttype = 0; /* transaction type. 0: TPC-B, 1: SELECT
! * only */
static CState state[MAXCLIENTS]; /* clients status */
--- 635,642 ----
int is_full_vacuum = 0; /* do full vacuum before testing? */
int debug = 0; /* debug flag */
int ttype = 0; /* transaction type. 0: TPC-B, 1: SELECT
! * only
! 2: skip updation of branches and tellers */
static CState state[MAXCLIENTS]; /* clients status */
***************
*** 641,647 ****
PGconn *con;
PGresult *res;
! while ((c = getopt(argc, argv, "ih:nvp:dc:t:s:U:P:CS")) != EOF)
{
switch (c)
{
--- 658,664 ----
PGconn *con;
PGresult *res;
! while ((c = getopt(argc, argv, "ih:nvp:dc:t:s:U:P:CNS")) != EOF)
{
switch (c)
{
***************
*** 666,671 ****
--- 683,691 ----
case 'S':
ttype = 1;
break;
+ case 'N':
+ ttype = 2;
+ break;
case 'c':
nclients = atoi(optarg);
if (nclients <= 0 || nclients > MAXCLIENTS)
***************
*** 851,858 ****
/* send start up quries in async manner */
for (i = 0; i < nclients; i++)
{
! if (ttype == 0)
! doOne(state, i, debug);
else if (ttype == 1)
doSelectOnly(state, i, debug);
}
--- 871,878 ----
/* send start up quries in async manner */
for (i = 0; i < nclients; i++)
{
! if (ttype == 0 || ttype == 2)
! doOne(state, i, debug, ttype);
else if (ttype == 1)
doSelectOnly(state, i, debug);
}
***************
*** 915,922 ****
{
if (state[i].con && FD_ISSET(PQsocket(state[i].con), &input_mask))
{
! if (ttype == 0)
! doOne(state, i, debug);
else if (ttype == 1)
doSelectOnly(state, i, debug);
}
--- 935,942 ----
{
if (state[i].con && FD_ISSET(PQsocket(state[i].con), &input_mask))
{
! if (ttype == 0 || ttype == 2)
! doOne(state, i, debug, ttype);
else if (ttype == 1)
doSelectOnly(state, i, debug);
}
[t-ishii@srapc1474 contrib]$
Attachments:
[text/plain] pgbench.patch (7.1K, ../../[email protected]/2-pgbench.patch)
download | inline diff:
Index: pgbench/README.pgbench
===================================================================
RCS file: /cvsroot/pgsql/contrib/pgbench/README.pgbench,v
retrieving revision 1.4
diff -c -r1.4 README.pgbench
*** pgbench/README.pgbench 2001/10/24 08:07:19 1.4
--- pgbench/README.pgbench 2002/01/09 01:31:26
***************
*** 122,127 ****
--- 122,130 ----
-S
Perform select only transactions instead of TPC-B.
+ -N
+ Skip updation of "branches" and "tellers" table. This
+ would result in lower contention of updates.
-C
Establish connection for each transaction, rather than
doing it just once at begining of pgbench in the normal
Index: pgbench/pgbench.c
===================================================================
RCS file: /cvsroot/pgsql/contrib/pgbench/pgbench.c,v
retrieving revision 1.13
diff -c -r1.13 pgbench.c
*** pgbench/pgbench.c 2001/11/05 17:46:23 1.13
--- pgbench/pgbench.c 2002/01/09 01:31:26
***************
*** 4,10 ****
* pgbench: a simple TPC-B like benchmark program for PostgreSQL
* written by Tatsuo Ishii
*
! * Copyright (c) 2000 Tatsuo Ishii
*
* Permission to use, copy, modify, and distribute this software and
* its documentation for any purpose and without fee is hereby
--- 4,10 ----
* pgbench: a simple TPC-B like benchmark program for PostgreSQL
* written by Tatsuo Ishii
*
! * Copyright (c) 2000-2002 Tatsuo Ishii
*
* Permission to use, copy, modify, and distribute this software and
* its documentation for any purpose and without fee is hereby
***************
*** 95,101 ****
static void
usage()
{
! fprintf(stderr, "usage: pgbench [-h hostname][-p port][-c nclients][-t ntransactions][-s scaling_factor][-n][-C][-v][-S][-U login][-P password][-d][dbname]\n");
fprintf(stderr, "(initialize mode): pgbench -i [-h hostname][-p port][-s scaling_factor][-U login][-P password][-d][dbname]\n");
}
--- 95,101 ----
static void
usage()
{
! fprintf(stderr, "usage: pgbench [-h hostname][-p port][-c nclients][-t ntransactions][-s scaling_factor][-n][-C][-v][-S][-N][-U login][-P password][-d][dbname]\n");
fprintf(stderr, "(initialize mode): pgbench -i [-h hostname][-p port][-s scaling_factor][-U login][-P password][-d][dbname]\n");
}
***************
*** 168,174 ****
/* process a transaction */
static void
! doOne(CState * state, int n, int debug)
{
char sql[256];
PGresult *res;
--- 168,174 ----
/* process a transaction */
static void
! doOne(CState * state, int n, int debug, int ttype)
{
char sql[256];
PGresult *res;
***************
*** 295,306 ****
sprintf(sql, "select abalance from accounts where aid = %d", st->aid);
break;
case 3:
! sprintf(sql, "update tellers set tbalance = tbalance + %d where tid = %d\n",
! st->delta, st->tid);
! break;
case 4:
! sprintf(sql, "update branches set bbalance = bbalance + %d where bid = %d", st->delta, st->bid);
! break;
case 5:
sprintf(sql, "insert into history(tid,bid,aid,delta,mtime) values(%d,%d,%d,%d,'now')",
st->tid, st->bid, st->aid, st->delta);
--- 295,312 ----
sprintf(sql, "select abalance from accounts where aid = %d", st->aid);
break;
case 3:
! if (ttype == 0)
! {
! sprintf(sql, "update tellers set tbalance = tbalance + %d where tid = %d\n",
! st->delta, st->tid);
! break;
! }
case 4:
! if (ttype == 0)
! {
! sprintf(sql, "update branches set bbalance = bbalance + %d where bid = %d", st->delta, st->bid);
! break;
! }
case 5:
sprintf(sql, "insert into history(tid,bid,aid,delta,mtime) values(%d,%d,%d,%d,'now')",
st->tid, st->bid, st->aid, st->delta);
***************
*** 549,554 ****
--- 555,561 ----
exit(1);
}
+ #ifdef NOT_USED
/*
* do a checkpoint to purge the old WAL logs
*/
***************
*** 558,563 ****
--- 565,571 ----
fprintf(stderr, "%s", PQerrorMessage(con));
exit(1);
}
+ #endif /* NOT_USED */
}
}
***************
*** 585,590 ****
--- 593,599 ----
t2;
int i;
int normal_xacts = 0;
+ char *s;
for (i = 0; i < nclients; i++)
normal_xacts += state[i].cnt;
***************
*** 594,601 ****
t2 = (tv3->tv_sec - tv2->tv_sec) * 1000000.0 + (tv3->tv_usec - tv2->tv_usec);
t2 = normal_xacts * 1000000.0 / t2;
! printf("transaction type: %s\n", ttype == 0 ? "TPC-B (sort of)" : "SELECT only");
printf("scaling factor: %d\n", tps);
printf("number of clients: %d\n", nclients);
printf("number of transactions per client: %d\n", nxacts);
--- 603,617 ----
t2 = (tv3->tv_sec - tv2->tv_sec) * 1000000.0 + (tv3->tv_usec - tv2->tv_usec);
t2 = normal_xacts * 1000000.0 / t2;
+
+ if (ttype == 0)
+ s = "TPC-B (sort of)";
+ else if (ttype == 2)
+ s = "Update only accounts";
+ else
+ s = "SELECT only";
! printf("transaction type: %s\n", s);
printf("scaling factor: %d\n", tps);
printf("number of clients: %d\n", nclients);
printf("number of transactions per client: %d\n", nxacts);
***************
*** 619,625 ****
int is_full_vacuum = 0; /* do full vacuum before testing? */
int debug = 0; /* debug flag */
int ttype = 0; /* transaction type. 0: TPC-B, 1: SELECT
! * only */
static CState state[MAXCLIENTS]; /* clients status */
--- 635,642 ----
int is_full_vacuum = 0; /* do full vacuum before testing? */
int debug = 0; /* debug flag */
int ttype = 0; /* transaction type. 0: TPC-B, 1: SELECT
! * only
! 2: skip updation of branches and tellers */
static CState state[MAXCLIENTS]; /* clients status */
***************
*** 641,647 ****
PGconn *con;
PGresult *res;
! while ((c = getopt(argc, argv, "ih:nvp:dc:t:s:U:P:CS")) != EOF)
{
switch (c)
{
--- 658,664 ----
PGconn *con;
PGresult *res;
! while ((c = getopt(argc, argv, "ih:nvp:dc:t:s:U:P:CNS")) != EOF)
{
switch (c)
{
***************
*** 666,671 ****
--- 683,691 ----
case 'S':
ttype = 1;
break;
+ case 'N':
+ ttype = 2;
+ break;
case 'c':
nclients = atoi(optarg);
if (nclients <= 0 || nclients > MAXCLIENTS)
***************
*** 851,858 ****
/* send start up quries in async manner */
for (i = 0; i < nclients; i++)
{
! if (ttype == 0)
! doOne(state, i, debug);
else if (ttype == 1)
doSelectOnly(state, i, debug);
}
--- 871,878 ----
/* send start up quries in async manner */
for (i = 0; i < nclients; i++)
{
! if (ttype == 0 || ttype == 2)
! doOne(state, i, debug, ttype);
else if (ttype == 1)
doSelectOnly(state, i, debug);
}
***************
*** 915,922 ****
{
if (state[i].con && FD_ISSET(PQsocket(state[i].con), &input_mask))
{
! if (ttype == 0)
! doOne(state, i, debug);
else if (ttype == 1)
doSelectOnly(state, i, debug);
}
--- 935,942 ----
{
if (state[i].con && FD_ISSET(PQsocket(state[i].con), &input_mask))
{
! if (ttype == 0 || ttype == 2)
! doOne(state, i, debug, ttype);
else if (ttype == 1)
doSelectOnly(state, i, debug);
}
[t-ishii@srapc1474 contrib]$
[image/png] result-Jan-09.png (6.7K, ../../[email protected]/3-result-Jan-09.png)
download | view image
^ permalink raw reply [nested|flat] 966+ messages in thread
* Re: 7.1 vs. 7.2 on AIX 5L
@ 2002-01-09 10:03 Hannu Krosing <[email protected]>
parent: Tatsuo Ishii <[email protected]>
1 sibling, 1 reply; 966+ messages in thread
From: Hannu Krosing @ 2002-01-09 10:03 UTC (permalink / raw)
To: Tatsuo Ishii <[email protected]>; +Cc: pgsql-hackers
Tatsuo Ishii wrote:
>
> Hi,
>
> I have made a new version of pgbench which allows not to update
> branches and tellers tables, which should significantly reduce the
> contentions. (See attached patches against current. Note that the
> paches also includes changes removing CHECKPOINT command while
> running in initialization mode (pgbench -i)). With the patches you
> could specify -N option not to update branches and tellers tables.
>
> With the new pgbench, I ran a test with current and 7.1 and saw
> not-so-small differences. Any idea to get better performance on 7.2
> and AIX 5L combo?
>
> 7.2 with lwlock.patch rev.2
> 7.1.3
> AIX 5L 4way with 4GB RAM
> testing script is same as my previous postings (except -N for pgbench,
> of course).
>
> ------------------------------------------------------------------------
> Name: pgbench.patch
> pgbench.patch Type: Plain Text (Text/Plain)
> Encoding: 7bit
>
> Name: result-Jan-09.png
> result-Jan-09.png Type: PNG Image (image/png)
> Encoding: base64
Could you add some labels to lines as Tom did ?
We can only guess which line is which.
--------------
Hannu
^ permalink raw reply [nested|flat] 966+ messages in thread
* Re: 7.1 vs. 7.2 on AIX 5L
@ 2002-01-09 12:25 Tatsuo Ishii <[email protected]>
parent: Hannu Krosing <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Tatsuo Ishii @ 2002-01-09 12:25 UTC (permalink / raw)
To: [email protected]; +Cc: pgsql-hackers
> Could you add some labels to lines as Tom did ?
>
> We can only guess which line is which.
I thought I already added labels. 7.1 is "+"(green one), and 7.2 is
"rhombus"(red one).
--
Tatsuo Ishii
^ permalink raw reply [nested|flat] 966+ messages in thread
* Re: 7.1 vs. 7.2 on AIX 5L
@ 2002-01-10 17:43 Tom Lane <[email protected]>
parent: Tatsuo Ishii <[email protected]>
1 sibling, 1 reply; 966+ messages in thread
From: Tom Lane @ 2002-01-10 17:43 UTC (permalink / raw)
To: Tatsuo Ishii <[email protected]>; +Cc: pgsql-hackers
Tatsuo Ishii <[email protected]> writes:
> I have made a new version of pgbench which allows not to update
> branches and tellers tables, which should significantly reduce the
> contentions.
I used this version of pgbench in some fresh runs on RedHat's 4-way SMP
Linux box. I did several test runs under varying conditions (pgbench
scale 500 or 50, checkpoint_segments/wal_files either default 3/0 or
30/5, fsync on or off). I compared current CVS tip (including the
now-committed lwlock rev 2 patch) to 7.1.3. The results are attached.
As you can see, current beats 7.1 pretty much across the board on that
hardware. The reason seems to be revealed by looking at vmstat output.
Typical "vmstat 5" output for 7.1.3 (here in a 6-client pgbench -N
run) is
procs memory swap io system cpu
r b w swpd free buff cache si so bi bo in cs us sy id
1 0 0 0 108444 8920 4917092 0 0 213 0 170 4814 0 1 99
1 0 0 0 103592 8948 4921912 0 0 234 357 230 4811 1 1 98
0 0 0 0 98776 8968 4926704 0 0 233 428 235 4854 1 1 97
0 0 0 0 94300 8980 4931168 0 0 216 423 229 4809 1 2 97
0 0 0 0 89960 8984 4935504 0 0 209 771 421 4723 2 2 96
0 0 0 0 69280 9016 4956140 0 0 205 842 457 4645 1 2 96
The system is capable of much greater I/O rates, so neither disks nor
CPUs are exactly exerting themselves here. In contrast, 7.2 shows:
procs memory swap io system cpu
r b w swpd free buff cache si so bi bo in cs us sy id
2 0 0 0 2927344 9148 1969356 0 0 0 5772 102 13753 61 32 7
7 0 0 0 3042272 9148 1969716 0 0 0 2267 2400 14083 58 32 10
5 0 0 0 3042168 9148 1970100 0 0 0 2734 1028 12994 53 37 11
I think that 7.1's poor showing here is undoubtedly due to the spinlock
backoff algorithm it used --- there is no other way to explain 99% idle
CPU than that all of the backends are caught in 10-msec select() waits.
> With the new pgbench, I ran a test with current and 7.1 and saw
> not-so-small differences. Any idea to get better performance on 7.2
> and AIX 5L combo?
I'm thinking more and more that there must be something weird about the
cs() routine that we use for spinlocks on AIX. Could someone dig into
that and find exactly what it does and whether it's got any performance
issues?
regards, tom lane
^ permalink raw reply [nested|flat] 966+ messages in thread
* Re: 7.1 vs. 7.2 on AIX 5L
@ 2002-01-10 20:08 Bruce Momjian <[email protected]>
parent: Tom Lane <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Bruce Momjian @ 2002-01-10 20:08 UTC (permalink / raw)
To: Tom Lane <[email protected]>; +Cc: Tatsuo Ishii <[email protected]>; pgsql-hackers
Tom Lane wrote:
> Tatsuo Ishii <[email protected]> writes:
> > I have made a new version of pgbench which allows not to update
> > branches and tellers tables, which should significantly reduce the
> > contentions.
>
> I used this version of pgbench in some fresh runs on RedHat's 4-way SMP
> Linux box. I did several test runs under varying conditions (pgbench
> scale 500 or 50, checkpoint_segments/wal_files either default 3/0 or
> 30/5, fsync on or off). I compared current CVS tip (including the
> now-committed lwlock rev 2 patch) to 7.1.3. The results are attached.
> As you can see, current beats 7.1 pretty much across the board on that
> hardware. The reason seems to be revealed by looking at vmstat output.
> Typical "vmstat 5" output for 7.1.3 (here in a 6-client pgbench -N
> run) is
Those are dramatic graphs. Is it the WAL increase that made 7.2 much
faster?
--
Bruce Momjian | http://candle.pha.pa.us
[email protected] | (610) 853-3000
+ If your life is a hard drive, | 830 Blythe Avenue
+ Christ can be your backup. | Drexel Hill, Pennsylvania 19026
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
* [PATCH 2/3] one more stress test for repack concurrently
@ 2025-12-13 17:46 Mikhail Nikalayeu <[email protected]>
0 siblings, 0 replies; 966+ messages in thread
From: Mikhail Nikalayeu @ 2025-12-13 17:46 UTC (permalink / raw)
---
contrib/amcheck/meson.build | 1 +
contrib/amcheck/t/008_repack_2.pl | 111 ++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
create mode 100644 contrib/amcheck/t/008_repack_2.pl
diff --git a/contrib/amcheck/meson.build b/contrib/amcheck/meson.build
index cb4bc32e98a..6799df214f9 100644
--- a/contrib/amcheck/meson.build
+++ b/contrib/amcheck/meson.build
@@ -51,6 +51,7 @@ tests += {
't/005_pitr.pl',
't/006_verify_gin.pl',
't/007_repack_1.pl',
+ 't/008_repack_2.pl',
],
},
}
diff --git a/contrib/amcheck/t/008_repack_2.pl b/contrib/amcheck/t/008_repack_2.pl
new file mode 100644
index 00000000000..a287ee2bb71
--- /dev/null
+++ b/contrib/amcheck/t/008_repack_2.pl
@@ -0,0 +1,111 @@
+# Copyright (c) 2021-2026, PostgreSQL Global Development Group
+
+# Test REPACK CONCURRENTLY with concurrent modifications
+use strict;
+use warnings FATAL => 'all';
+
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+
+use Test::More;
+
+# PG_TEST_EXTRA carries a numerical stress value; 0 disables the test,
+# 1 means the test takes about 6 seconds, and the increase should be
+# roughly linear.
+my $matched = ($ENV{PG_TEST_EXTRA} // '') =~ /\bstress_concurrently(?:=(?<stressval>[0-9]*))?\b/;
+my $stressval = $+{stressval} // 1;
+if (!$matched or $stressval == 0)
+{
+ plan skip_all => 'skipping disabled REPACK CONCURRENTLY stress test';
+}
+
+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->append_conf(
+ 'postgresql.conf', qq(
+wal_level = logical
+));
+
+my $duration = 6 * $stressval;
+my $no_hot = int(rand(2));
+
+$node->start;
+$node->safe_psql('postgres', q(CREATE TABLE tbl(id SERIAL PRIMARY KEY, val int)));
+if ($no_hot)
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(val);));
+}
+else
+{
+ $node->safe_psql('postgres', q(CREATE INDEX test_idx ON tbl(id);));
+}
+
+# Load amcheck
+$node->safe_psql('postgres', q(CREATE EXTENSION amcheck));
+
+my $sum = $node->safe_psql('postgres', q(
+ SELECT SUM(val) AS sum FROM tbl
+));
+
+$node->safe_psql('postgres', q(CREATE UNLOGGED SEQUENCE last_j START 1 INCREMENT 1;));
+
+
+$node->pgbench(
+"--no-vacuum --client=30 --jobs=4 --exit-on-abort -T $duration",
+0,
+[qr{actually processed}],
+[qr{^$}],
+'concurrent operations with REINDEX/CREATE INDEX CONCURRENTLY',
+{
+ 'concurrent_ops' => qq(
+ SELECT pg_try_advisory_lock(42)::integer AS gotlock \\gset
+ \\if :gotlock
+ REPACK (CONCURRENTLY) tbl USING INDEX tbl_pkey;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl USING INDEX test_idx;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ REPACK (CONCURRENTLY) tbl;
+ SELECT bt_index_parent_check('tbl_pkey', heapallindexed => true);
+ SELECT bt_index_parent_check('test_idx', heapallindexed => true);
+ \\sleep 10 ms
+
+ SELECT pg_advisory_unlock(42);
+ \\else
+ SELECT pg_advisory_lock(43);
+ BEGIN;
+ INSERT INTO tbl(val) VALUES (nextval('last_j')) RETURNING val \\gset p_
+ COMMIT;
+ SELECT pg_advisory_unlock(43);
+ \\sleep 1 ms
+
+ BEGIN
+ --TRANSACTION ISOLATION LEVEL REPEATABLE READ
+ ;
+ SELECT 1;
+ \\sleep 1 ms
+ SELECT COUNT(*) AS count FROM tbl WHERE val <= :p_j \\gset p_
+ \\if :p_count != :p_j
+ COMMIT;
+ SELECT (:p_count) / 0;
+ \\endif
+
+ COMMIT;
+ \\endif
+ )
+});
+
+$node->stop;
+done_testing();
--
2.47.3
--tbdehtstrqwksfdh
Content-Type: text/x-diff; charset=utf-8
Content-Disposition: attachment;
filename="0003-Distinguish-properly-when-database-specific-transact.patch"
^ permalink raw reply [nested|flat] 966+ messages in thread
end of thread, other threads:[~2025-12-13 17:46 UTC | newest]
Thread overview: 966+ messages (download: mbox mbox.gz follow: Atom feed)
-- links below jump to the message on this page --
2002-01-09 01:35 7.1 vs. 7.2 on AIX 5L Tatsuo Ishii <[email protected]>
2002-01-09 10:03 ` Hannu Krosing <[email protected]>
2002-01-09 12:25 ` Tatsuo Ishii <[email protected]>
2002-01-10 17:43 ` Tom Lane <[email protected]>
2002-01-10 20:08 ` Bruce Momjian <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
2025-12-13 17:46 [PATCH 2/3] one more stress test for repack concurrently Mikhail Nikalayeu <[email protected]>
This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox