@@ -584,12 +584,14 @@ partition_table_concurrently(PG_FUNCTION_ARGS)
584584#define tostr (str ) ( #str ) /* convert function's name to literal */
585585
586586 Oid relid = PG_GETARG_OID (0 );
587- int empty_slot_idx = -1 ;
587+ int empty_slot_idx = -1 ; /* do we have a slot for BGWorker? */
588588 int i ;
589589
590590 /* Check if relation is a partitioned table */
591591 shout_if_prel_is_invalid (relid ,
592+ /* We also lock the parent relation */
592593 get_pathman_relation_info_after_lock (relid , true),
594+ /* Partitioning type does not matter here */
593595 PT_INDIFFERENT );
594596
595597 /*
@@ -601,30 +603,38 @@ partition_table_concurrently(PG_FUNCTION_ARGS)
601603 ConcurrentPartSlot * cur_slot = & concurrent_part_slots [i ];
602604 bool keep_this_lock = false;
603605
606+ /* Lock current slot */
604607 SpinLockAcquire (& cur_slot -> mutex );
605608
606- /* Should we take this slot into account? */
609+ /* Should we take this slot into account? (it should be FREE) */
607610 if (empty_slot_idx < 0 && cur_slot -> worker_status == CPS_FREE )
608611 {
609- empty_slot_idx = i ;
610- keep_this_lock = true;
612+ empty_slot_idx = i ; /* yes, remember this slot */
613+ keep_this_lock = true; /* also don't unlock it */
611614 }
612615
616+ /* Oops, looks like we already have BGWorker for this table */
613617 if (cur_slot -> relid == relid &&
614618 cur_slot -> dbid == MyDatabaseId )
615619 {
616- if (empty_slot_idx >= 0 )
617- SpinLockRelease (& cur_slot -> mutex );
620+ /* Unlock current slot */
621+ SpinLockRelease (& cur_slot -> mutex );
622+
623+ /* Release borrowed slot for new BGWorker too */
624+ if (empty_slot_idx >= 0 && empty_slot_idx != i )
625+ SpinLockRelease (& concurrent_part_slots [empty_slot_idx ].mutex );
618626
619627 elog (ERROR ,
620628 "Table \"%s\" is already being partitioned" ,
621629 get_rel_name (relid ));
622630 }
623631
632+ /* Normally we don't want to keep it */
624633 if (!keep_this_lock )
625634 SpinLockRelease (& cur_slot -> mutex );
626635 }
627636
637+ /* Looks like we could not find an empty slot */
628638 if (empty_slot_idx < 0 )
629639 elog (ERROR , "No empty worker slots found" );
630640 else
@@ -634,6 +644,7 @@ partition_table_concurrently(PG_FUNCTION_ARGS)
634644 GetAuthenticatedUserId (), CPS_WORKING ,
635645 MyDatabaseId , relid , 1000 , 1.0 );
636646
647+ /* Now we can safely unlock slot for new BGWorker */
637648 SpinLockRelease (& concurrent_part_slots [empty_slot_idx ].mutex );
638649 }
639650
0 commit comments