@@ -206,19 +206,8 @@ main(int argc, char *argv[])
206
206
207
207
setup_cancel_handler (NULL );
208
208
209
- if (concurrentCons > 1 )
210
- {
211
- /*
212
- * Index-level REINDEX is not supported with multiple jobs as we
213
- * cannot control the concurrent processing of multiple indexes
214
- * depending on the same relation.
215
- */
216
- if (indexes .head != NULL )
217
- pg_fatal ("cannot use multiple jobs to reindex indexes" );
218
-
219
- if (syscatalog )
220
- pg_fatal ("cannot use multiple jobs to reindex system catalogs" );
221
- }
209
+ if (concurrentCons > 1 && syscatalog )
210
+ pg_fatal ("cannot use multiple jobs to reindex system catalogs" );
222
211
223
212
if (alldb )
224
213
{
@@ -258,7 +247,7 @@ main(int argc, char *argv[])
258
247
if (indexes .head != NULL )
259
248
reindex_one_database (& cparams , REINDEX_INDEX , & indexes ,
260
249
progname , echo , verbose ,
261
- concurrently , 1 , tablespace );
250
+ concurrently , concurrentCons , tablespace );
262
251
263
252
if (tables .head != NULL )
264
253
reindex_one_database (& cparams , REINDEX_TABLE , & tables ,
@@ -288,12 +277,16 @@ reindex_one_database(ConnParams *cparams, ReindexType type,
288
277
{
289
278
PGconn * conn ;
290
279
SimpleStringListCell * cell ;
280
+ SimpleStringListCell * indices_tables_cell ;
291
281
bool parallel = concurrentCons > 1 ;
292
282
SimpleStringList * process_list = user_list ;
283
+ SimpleStringList * indices_tables_list = NULL ;
293
284
ReindexType process_type = type ;
294
285
ParallelSlotArray * sa ;
295
286
bool failed = false;
296
287
int items_count = 0 ;
288
+ char * prev_index_table_name = NULL ;
289
+ ParallelSlot * free_slot = NULL ;
297
290
298
291
conn = connectDatabase (cparams , progname , echo , false, true);
299
292
@@ -363,8 +356,25 @@ reindex_one_database(ConnParams *cparams, ReindexType type,
363
356
return ;
364
357
break ;
365
358
366
- case REINDEX_SYSTEM :
367
359
case REINDEX_INDEX :
360
+ Assert (user_list != NULL );
361
+
362
+ /*
363
+ * Build a list of relations from the indices. This will
364
+ * accordingly reorder the list of indices too.
365
+ */
366
+ indices_tables_list = get_parallel_object_list (conn , process_type ,
367
+ user_list , echo );
368
+
369
+ if (indices_tables_list )
370
+ indices_tables_cell = indices_tables_list -> head ;
371
+
372
+ /* Bail out if nothing to process */
373
+ if (process_list == NULL )
374
+ return ;
375
+ break ;
376
+
377
+ case REINDEX_SYSTEM :
368
378
/* not supported */
369
379
Assert (false);
370
380
break ;
@@ -404,22 +414,41 @@ reindex_one_database(ConnParams *cparams, ReindexType type,
404
414
do
405
415
{
406
416
const char * objname = cell -> val ;
407
- ParallelSlot * free_slot = NULL ;
417
+ bool need_new_slot = true ;
408
418
409
419
if (CancelRequested )
410
420
{
411
421
failed = true;
412
422
goto finish ;
413
423
}
414
424
415
- free_slot = ParallelSlotsGetIdle (sa , NULL );
416
- if (!free_slot )
425
+ /*
426
+ * For parallel index-level REINDEX, the indices of the same table are
427
+ * ordered together and they are to be processed by the same job. So,
428
+ * we don't switch the job as soon as the index belongs to the same
429
+ * table as the previous one.
430
+ */
431
+ if (parallel && process_type == REINDEX_INDEX )
432
+ {
433
+ if (prev_index_table_name != NULL &&
434
+ strcmp (prev_index_table_name , indices_tables_cell -> val ) == 0 )
435
+ need_new_slot = false;
436
+ prev_index_table_name = indices_tables_cell -> val ;
437
+ indices_tables_cell = indices_tables_cell -> next ;
438
+ }
439
+
440
+ if (need_new_slot )
417
441
{
418
- failed = true;
419
- goto finish ;
442
+ free_slot = ParallelSlotsGetIdle (sa , NULL );
443
+ if (!free_slot )
444
+ {
445
+ failed = true;
446
+ goto finish ;
447
+ }
448
+
449
+ ParallelSlotSetHandler (free_slot , TableCommandResultHandler , NULL );
420
450
}
421
451
422
- ParallelSlotSetHandler (free_slot , TableCommandResultHandler , NULL );
423
452
run_reindex_command (free_slot -> connection , process_type , objname ,
424
453
echo , verbose , concurrently , true, tablespace );
425
454
@@ -436,6 +465,12 @@ reindex_one_database(ConnParams *cparams, ReindexType type,
436
465
pg_free (process_list );
437
466
}
438
467
468
+ if (indices_tables_list )
469
+ {
470
+ simple_string_list_destroy (indices_tables_list );
471
+ pg_free (indices_tables_list );
472
+ }
473
+
439
474
ParallelSlotsTerminate (sa );
440
475
pfree (sa );
441
476
@@ -647,8 +682,61 @@ get_parallel_object_list(PGconn *conn, ReindexType type,
647
682
}
648
683
break ;
649
684
650
- case REINDEX_SYSTEM :
651
685
case REINDEX_INDEX :
686
+ {
687
+ SimpleStringListCell * cell ;
688
+
689
+ Assert (user_list != NULL );
690
+
691
+ /*
692
+ * Straight-forward index-level REINDEX is not supported with
693
+ * multiple jobs as we cannot control the concurrent
694
+ * processing of multiple indexes depending on the same
695
+ * relation. But we can extract the appropriate table name
696
+ * for the index and put REINDEX INDEX commands into different
697
+ * jobs, according to the parent tables.
698
+ *
699
+ * We will order the results to group the same tables
700
+ * together. We fetch index names as well to build a new list
701
+ * of them with matching order.
702
+ */
703
+ appendPQExpBufferStr (& catalog_query ,
704
+ "SELECT t.relname, n.nspname, i.relname\n"
705
+ "FROM pg_catalog.pg_index x\n"
706
+ "JOIN pg_catalog.pg_class t ON t.oid = x.indrelid\n"
707
+ "JOIN pg_catalog.pg_class i ON i.oid = x.indexrelid\n"
708
+ "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.relnamespace\n"
709
+ "WHERE x.indexrelid OPERATOR(pg_catalog.=) ANY(ARRAY['" );
710
+
711
+ for (cell = user_list -> head ; cell ; cell = cell -> next )
712
+ {
713
+ if (cell != user_list -> head )
714
+ appendPQExpBufferStr (& catalog_query , "', '" );
715
+
716
+ appendQualifiedRelation (& catalog_query , cell -> val , conn , echo );
717
+ }
718
+
719
+ /*
720
+ * Order tables by the size of its greatest index. Within the
721
+ * table, order indexes by their sizes.
722
+ */
723
+ appendPQExpBufferStr (& catalog_query ,
724
+ "']::pg_catalog.regclass[])\n"
725
+ "ORDER BY max(i.relpages) OVER \n"
726
+ " (PARTITION BY n.nspname, t.relname),\n"
727
+ " n.nspname, t.relname, i.relpages;\n" );
728
+
729
+ /*
730
+ * We're going to re-order the user_list to match the order of
731
+ * tables. So, empty the user_list to fill it from the query
732
+ * result.
733
+ */
734
+ simple_string_list_destroy (user_list );
735
+ user_list -> head = user_list -> tail = NULL ;
736
+ }
737
+ break ;
738
+
739
+ case REINDEX_SYSTEM :
652
740
case REINDEX_TABLE :
653
741
Assert (false);
654
742
break ;
@@ -680,6 +768,20 @@ get_parallel_object_list(PGconn *conn, ReindexType type,
680
768
681
769
simple_string_list_append (tables , buf .data );
682
770
resetPQExpBuffer (& buf );
771
+
772
+ if (type == REINDEX_INDEX )
773
+ {
774
+ /*
775
+ * For index-level REINDEX, rebuild the list of indexes to match
776
+ * the order of tables list.
777
+ */
778
+ appendPQExpBufferStr (& buf ,
779
+ fmtQualifiedId (PQgetvalue (res , i , 1 ),
780
+ PQgetvalue (res , i , 2 )));
781
+
782
+ simple_string_list_append (user_list , buf .data );
783
+ resetPQExpBuffer (& buf );
784
+ }
683
785
}
684
786
termPQExpBuffer (& buf );
685
787
PQclear (res );
0 commit comments