Skip to content

Commit 09ef2f8

Browse files
committed
reindexdb: Fix the index-level REINDEX with multiple jobs
47f99a4 introduced a parallel index-level REINDEX. The code was written assuming that running run_reindex_command() with 'async == true' can schedule a number of queries for a connection. That's not true, and the second query sent using run_reindex_command() will wait for the completion of the previous one. This commit fixes that by putting REINDEX commands for the same table into a single query. Also, this commit removes the 'async' argument from run_reindex_command(), as only its call always passes 'async == true'. Reported-by: Álvaro Herrera <alvherre@alvh.no-ip.org> Discussion: https://postgr.es/m/202503071820.j25zn3lo4hvn%40alvherre.pgsql Reviewed-by: Álvaro Herrera <alvherre@alvh.no-ip.org> Backpatch-through: 17
1 parent c826cd1 commit 09ef2f8

File tree

1 file changed

+73
-62
lines changed

1 file changed

+73
-62
lines changed

src/bin/scripts/reindexdb.c

Lines changed: 73 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,13 @@ static void reindex_all_databases(ConnParams *cparams,
5050
bool syscatalog, SimpleStringList *schemas,
5151
SimpleStringList *tables,
5252
SimpleStringList *indexes);
53-
static void run_reindex_command(PGconn *conn, ReindexType type,
53+
static void gen_reindex_command(PGconn *conn, ReindexType type,
5454
const char *name, bool echo, bool verbose,
55-
bool concurrently, bool async,
56-
const char *tablespace);
55+
bool concurrently, const char *tablespace,
56+
PQExpBufferData *sql);
57+
static void run_reindex_command(PGconn *conn, ReindexType type,
58+
const char *name, bool echo,
59+
PQExpBufferData *sq);
5760

5861
static void help(const char *progname);
5962

@@ -285,7 +288,6 @@ reindex_one_database(ConnParams *cparams, ReindexType type,
285288
ParallelSlotArray *sa;
286289
bool failed = false;
287290
int items_count = 0;
288-
char *prev_index_table_name = NULL;
289291
ParallelSlot *free_slot = NULL;
290292

291293
conn = connectDatabase(cparams, progname, echo, false, true);
@@ -421,44 +423,54 @@ reindex_one_database(ConnParams *cparams, ReindexType type,
421423
cell = process_list->head;
422424
do
423425
{
426+
PQExpBufferData sql;
424427
const char *objname = cell->val;
425-
bool need_new_slot = true;
426428

427429
if (CancelRequested)
428430
{
429431
failed = true;
430432
goto finish;
431433
}
432434

433-
/*
434-
* For parallel index-level REINDEX, the indices of the same table are
435-
* ordered together and they are to be processed by the same job. So,
436-
* we don't switch the job as soon as the index belongs to the same
437-
* table as the previous one.
438-
*/
439-
if (parallel && process_type == REINDEX_INDEX)
435+
free_slot = ParallelSlotsGetIdle(sa, NULL);
436+
if (!free_slot)
440437
{
441-
if (prev_index_table_name != NULL &&
442-
strcmp(prev_index_table_name, indices_tables_cell->val) == 0)
443-
need_new_slot = false;
444-
prev_index_table_name = indices_tables_cell->val;
445-
indices_tables_cell = indices_tables_cell->next;
438+
failed = true;
439+
goto finish;
446440
}
447441

448-
if (need_new_slot)
442+
ParallelSlotSetHandler(free_slot, TableCommandResultHandler, NULL);
443+
initPQExpBuffer(&sql);
444+
if (parallel && process_type == REINDEX_INDEX)
449445
{
450-
free_slot = ParallelSlotsGetIdle(sa, NULL);
451-
if (!free_slot)
446+
/*
447+
* For parallel index-level REINDEX, the indices of the same table
448+
* are ordered together and they are to be processed by the same
449+
* job. So, we put all the relevant REINDEX commands into the
450+
* same SQL query to be processed by this job at once.
451+
*/
452+
gen_reindex_command(free_slot->connection, process_type, objname,
453+
echo, verbose, concurrently, tablespace, &sql);
454+
while (indices_tables_cell->next &&
455+
strcmp(indices_tables_cell->val, indices_tables_cell->next->val) == 0)
452456
{
453-
failed = true;
454-
goto finish;
457+
indices_tables_cell = indices_tables_cell->next;
458+
cell = cell->next;
459+
objname = cell->val;
460+
appendPQExpBufferChar(&sql, '\n');
461+
gen_reindex_command(free_slot->connection, process_type, objname,
462+
echo, verbose, concurrently, tablespace, &sql);
455463
}
456-
457-
ParallelSlotSetHandler(free_slot, TableCommandResultHandler, NULL);
464+
indices_tables_cell = indices_tables_cell->next;
465+
}
466+
else
467+
{
468+
gen_reindex_command(free_slot->connection, process_type, objname,
469+
echo, verbose, concurrently, tablespace, &sql);
458470
}
459-
460471
run_reindex_command(free_slot->connection, process_type, objname,
461-
echo, verbose, concurrently, true, tablespace);
472+
echo, &sql);
473+
termPQExpBuffer(&sql);
462474

463475
cell = cell->next;
464476
} while (cell != NULL);
@@ -486,57 +498,57 @@ reindex_one_database(ConnParams *cparams, ReindexType type,
486498
exit(1);
487499
}
488500

501+
/*
502+
* Append a SQL command required to reindex a given database object to the
503+
* '*sql' string.
504+
*/
489505
static void
490-
run_reindex_command(PGconn *conn, ReindexType type, const char *name,
491-
bool echo, bool verbose, bool concurrently, bool async,
492-
const char *tablespace)
506+
gen_reindex_command(PGconn *conn, ReindexType type, const char *name,
507+
bool echo, bool verbose, bool concurrently,
508+
const char *tablespace, PQExpBufferData *sql)
493509
{
494510
const char *paren = "(";
495511
const char *comma = ", ";
496512
const char *sep = paren;
497-
PQExpBufferData sql;
498-
bool status;
499513

500514
Assert(name);
501515

502516
/* build the REINDEX query */
503-
initPQExpBuffer(&sql);
504-
505-
appendPQExpBufferStr(&sql, "REINDEX ");
517+
appendPQExpBufferStr(sql, "REINDEX ");
506518

507519
if (verbose)
508520
{
509-
appendPQExpBuffer(&sql, "%sVERBOSE", sep);
521+
appendPQExpBuffer(sql, "%sVERBOSE", sep);
510522
sep = comma;
511523
}
512524

513525
if (tablespace)
514526
{
515-
appendPQExpBuffer(&sql, "%sTABLESPACE %s", sep,
527+
appendPQExpBuffer(sql, "%sTABLESPACE %s", sep,
516528
fmtIdEnc(tablespace, PQclientEncoding(conn)));
517529
sep = comma;
518530
}
519531

520532
if (sep != paren)
521-
appendPQExpBufferStr(&sql, ") ");
533+
appendPQExpBufferStr(sql, ") ");
522534

523535
/* object type */
524536
switch (type)
525537
{
526538
case REINDEX_DATABASE:
527-
appendPQExpBufferStr(&sql, "DATABASE ");
539+
appendPQExpBufferStr(sql, "DATABASE ");
528540
break;
529541
case REINDEX_INDEX:
530-
appendPQExpBufferStr(&sql, "INDEX ");
542+
appendPQExpBufferStr(sql, "INDEX ");
531543
break;
532544
case REINDEX_SCHEMA:
533-
appendPQExpBufferStr(&sql, "SCHEMA ");
545+
appendPQExpBufferStr(sql, "SCHEMA ");
534546
break;
535547
case REINDEX_SYSTEM:
536-
appendPQExpBufferStr(&sql, "SYSTEM ");
548+
appendPQExpBufferStr(sql, "SYSTEM ");
537549
break;
538550
case REINDEX_TABLE:
539-
appendPQExpBufferStr(&sql, "TABLE ");
551+
appendPQExpBufferStr(sql, "TABLE ");
540552
break;
541553
}
542554

@@ -546,37 +558,43 @@ run_reindex_command(PGconn *conn, ReindexType type, const char *name,
546558
* object type.
547559
*/
548560
if (concurrently)
549-
appendPQExpBufferStr(&sql, "CONCURRENTLY ");
561+
appendPQExpBufferStr(sql, "CONCURRENTLY ");
550562

551563
/* object name */
552564
switch (type)
553565
{
554566
case REINDEX_DATABASE:
555567
case REINDEX_SYSTEM:
556-
appendPQExpBufferStr(&sql,
568+
appendPQExpBufferStr(sql,
557569
fmtIdEnc(name, PQclientEncoding(conn)));
558570
break;
559571
case REINDEX_INDEX:
560572
case REINDEX_TABLE:
561-
appendQualifiedRelation(&sql, name, conn, echo);
573+
appendQualifiedRelation(sql, name, conn, echo);
562574
break;
563575
case REINDEX_SCHEMA:
564-
appendPQExpBufferStr(&sql, name);
576+
appendPQExpBufferStr(sql, name);
565577
break;
566578
}
567579

568580
/* finish the query */
569-
appendPQExpBufferChar(&sql, ';');
581+
appendPQExpBufferChar(sql, ';');
582+
}
570583

571-
if (async)
572-
{
573-
if (echo)
574-
printf("%s\n", sql.data);
584+
/*
585+
* Run one or more reindex commands accumulated in the '*sql' string against
586+
* a given database connection.
587+
*/
588+
static void
589+
run_reindex_command(PGconn *conn, ReindexType type, const char *name,
590+
bool echo, PQExpBufferData *sql)
591+
{
592+
bool status;
575593

576-
status = PQsendQuery(conn, sql.data) == 1;
577-
}
578-
else
579-
status = executeMaintenanceCommand(conn, sql.data, echo);
594+
if (echo)
595+
printf("%s\n", sql->data);
596+
597+
status = PQsendQuery(conn, sql->data) == 1;
580598

581599
if (!status)
582600
{
@@ -603,14 +621,7 @@ run_reindex_command(PGconn *conn, ReindexType type, const char *name,
603621
name, PQdb(conn), PQerrorMessage(conn));
604622
break;
605623
}
606-
if (!async)
607-
{
608-
PQfinish(conn);
609-
exit(1);
610-
}
611624
}
612-
613-
termPQExpBuffer(&sql);
614625
}
615626

616627
/*

0 commit comments

Comments
 (0)