Skip to content

Commit d79d342

Browse files
committed
Add advisory locking to repack_one_table()
Avoids danger (or just pointlessness) of having someone run a table-wide repack and an indexes-only repack of the same table at the same time.
1 parent 62b5e4f commit d79d342

File tree

1 file changed

+30
-5
lines changed

1 file changed

+30
-5
lines changed

bin/pg_repack.c

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1001,9 +1001,31 @@ repack_one_table(const repack_table *table, const char *orderby)
10011001
elog(DEBUG2, "sql_pop : %s", table->sql_pop);
10021002

10031003
/*
1004-
* 1. Setup workspaces and a trigger.
1004+
* 1. Setup advisory lock and trigger on main table.
10051005
*/
10061006
elog(DEBUG2, "---- setup ----");
1007+
1008+
/* Obtain an advisory lock on the table's OID, to make sure no other
1009+
* pg_repack is working on the table. (Not a real concern with only
1010+
* full-table repacks, but mainly for index-only repacks.)
1011+
*/
1012+
params[0] = utoa(table->target_oid, buffer);
1013+
res = pgut_execute(connection, "SELECT pg_try_advisory_lock($1::bigint)",
1014+
1, params);
1015+
if (PQresultStatus(res) != PGRES_TUPLES_OK)
1016+
{
1017+
elog(ERROR, "%s", PQerrorMessage(connection));
1018+
have_error = true;
1019+
goto cleanup;
1020+
}
1021+
else if (strcmp(getstr(res, 0, 0), "t") != 0)
1022+
{
1023+
elog(WARNING, "Another pg_repack command may be running on the table. Please try again later.");
1024+
have_error = true;
1025+
goto cleanup;
1026+
}
1027+
CLEARPGRES(res);
1028+
10071029
if (!(lock_exclusive(connection, utoa(table->target_oid, buffer), table->lock_table, TRUE)))
10081030
{
10091031
elog(WARNING, "lock_exclusive() failed for %s", table->target_name);
@@ -1015,8 +1037,6 @@ repack_one_table(const repack_table *table, const char *orderby)
10151037
* Check z_repack_trigger is the trigger executed last so that
10161038
* other before triggers cannot modify triggered tuples.
10171039
*/
1018-
params[0] = utoa(table->target_oid, buffer);
1019-
10201040
res = execute("SELECT repack.conflicted_triggers($1)", 1, params);
10211041
if (PQntuples(res) > 0)
10221042
{
@@ -1289,7 +1309,6 @@ repack_one_table(const repack_table *table, const char *orderby)
12891309
elog(DEBUG2, "---- drop ----");
12901310

12911311
command("BEGIN ISOLATION LEVEL READ COMMITTED", 0, NULL);
1292-
params[0] = utoa(table->target_oid, buffer);
12931312
command("SELECT repack.repack_drop($1)", 1, params);
12941313
command("COMMIT", 0, NULL);
12951314

@@ -1308,6 +1327,10 @@ repack_one_table(const repack_table *table, const char *orderby)
13081327
command("COMMIT", 0, NULL);
13091328
}
13101329

1330+
/* Release advisory lock on table. */
1331+
res = pgut_execute(connection, "SELECT pg_advisory_unlock($1::bigint)",
1332+
1, params);
1333+
13111334
cleanup:
13121335
CLEARPGRES(res);
13131336
termStringInfo(&sql);
@@ -1772,7 +1795,7 @@ repack_all_indexes(char *errbuf, size_t errsize){
17721795
elog(ERROR, "%s", PQerrorMessage(connection));
17731796
goto cleanup;
17741797
}
1775-
else if (strcmp(getstr(res2, 0, 0), "f") == 0)
1798+
else if (strcmp(getstr(res2, 0, 0), "t") != 0)
17761799
{
17771800
snprintf(errbuf, errsize, "Another pg_repack command may be running on the table. Please try again later.");
17781801
goto cleanup;
@@ -1798,8 +1821,10 @@ repack_all_indexes(char *errbuf, size_t errsize){
17981821
elog(WARNING, "skipping invalid index: %s", getstr(res, i, 0));
17991822
}
18001823
ret = true;
1824+
18011825
cleanup:
18021826
CLEARPGRES(res);
1827+
CLEARPGRES(res2);
18031828
disconnect();
18041829
termStringInfo(&sql);
18051830
return ret;

0 commit comments

Comments
 (0)