@@ -820,25 +820,33 @@ enum DemultiplexCommand {
820
820
ListenOnce ( JobId , oneshot:: Sender < WorkerMessage > ) ,
821
821
}
822
822
823
- #[ derive( Debug , Copy , Clone ) ]
824
- pub struct CoordinatorId {
825
- start : u64 ,
826
- id : u64 ,
823
+ /// The [`Coordinator`][] usually represents a mostly-global resource,
824
+ /// such as a Docker container. To avoid conflicts, each container
825
+ /// must have a unique name, but that uniqueness can only be
826
+ /// guaranteed by whoever is creating [`Coordinator`][]s via the
827
+ /// [`CoordinatorFactory`][].
828
+ pub trait IdProvider : Send + Sync + fmt:: Debug + ' static {
829
+ fn next ( & self ) -> String ;
827
830
}
828
831
829
- /// Enforces a limited number of concurrent `Coordinator`s.
832
+ /// A reasonable choice when there's a single [`IdProvider`][] in the
833
+ /// entire process.
834
+ ///
835
+ /// This represents uniqueness via a combination of
836
+ ///
837
+ /// 1. **process start time** — this helps avoid conflicts from other
838
+ /// processes, assuming they were started at least one second apart.
839
+ ///
840
+ /// 2. **instance counter** — this avoids conflicts from other
841
+ /// [`Coordinator`][]s started inside this process.
830
842
#[ derive( Debug ) ]
831
- pub struct CoordinatorFactory {
832
- semaphore : Arc < Semaphore > ,
833
-
843
+ pub struct GlobalIdProvider {
834
844
start : u64 ,
835
845
id : AtomicU64 ,
836
846
}
837
847
838
- impl CoordinatorFactory {
839
- pub fn new ( maximum : usize ) -> Self {
840
- let semaphore = Arc :: new ( Semaphore :: new ( maximum) ) ;
841
-
848
+ impl GlobalIdProvider {
849
+ pub fn new ( ) -> Self {
842
850
let now = std:: time:: SystemTime :: now ( ) ;
843
851
let start = now
844
852
. duration_since ( std:: time:: UNIX_EPOCH )
@@ -847,28 +855,40 @@ impl CoordinatorFactory {
847
855
848
856
let id = AtomicU64 :: new ( 0 ) ;
849
857
850
- Self {
851
- semaphore,
852
- start,
853
- id,
854
- }
858
+ Self { start, id }
855
859
}
860
+ }
856
861
857
- fn next_id ( & self ) -> CoordinatorId {
862
+ impl IdProvider for GlobalIdProvider {
863
+ fn next ( & self ) -> String {
858
864
let start = self . start ;
859
865
let id = self . id . fetch_add ( 1 , Ordering :: SeqCst ) ;
860
866
861
- CoordinatorId { start, id }
867
+ format ! ( "{start}-{id}" )
868
+ }
869
+ }
870
+
871
+ /// Enforces a limited number of concurrent `Coordinator`s.
872
+ #[ derive( Debug ) ]
873
+ pub struct CoordinatorFactory {
874
+ semaphore : Arc < Semaphore > ,
875
+ ids : Arc < dyn IdProvider > ,
876
+ }
877
+
878
+ impl CoordinatorFactory {
879
+ pub fn new ( ids : Arc < dyn IdProvider > , maximum : usize ) -> Self {
880
+ let semaphore = Arc :: new ( Semaphore :: new ( maximum) ) ;
881
+
882
+ Self { semaphore, ids }
862
883
}
863
884
864
885
pub fn build < B > ( & self ) -> Coordinator < B >
865
886
where
866
- B : Backend + From < CoordinatorId > ,
887
+ B : Backend + From < Arc < dyn IdProvider > > ,
867
888
{
868
889
let semaphore = self . semaphore . clone ( ) ;
869
890
870
- let id = self . next_id ( ) ;
871
- let backend = B :: from ( id) ;
891
+ let backend = B :: from ( self . ids . clone ( ) ) ;
872
892
873
893
Coordinator :: new ( semaphore, backend)
874
894
}
@@ -2586,25 +2606,20 @@ fn basic_secure_docker_command() -> Command {
2586
2606
}
2587
2607
2588
2608
pub struct DockerBackend {
2589
- id : CoordinatorId ,
2590
- instance : AtomicU64 ,
2609
+ ids : Arc < dyn IdProvider > ,
2591
2610
}
2592
2611
2593
- impl From < CoordinatorId > for DockerBackend {
2594
- fn from ( id : CoordinatorId ) -> Self {
2595
- Self {
2596
- id,
2597
- instance : Default :: default ( ) ,
2598
- }
2612
+ impl From < Arc < dyn IdProvider > > for DockerBackend {
2613
+ fn from ( ids : Arc < dyn IdProvider > ) -> Self {
2614
+ Self { ids }
2599
2615
}
2600
2616
}
2601
2617
2602
2618
impl DockerBackend {
2603
2619
fn next_name ( & self ) -> String {
2604
- let CoordinatorId { start, id } = self . id ;
2605
- let instance = self . instance . fetch_add ( 1 , Ordering :: SeqCst ) ;
2620
+ let id = self . ids . next ( ) ;
2606
2621
2607
- format ! ( "playground-{start}-{id}-{instance }" )
2622
+ format ! ( "playground-{id }" )
2608
2623
}
2609
2624
}
2610
2625
@@ -2617,6 +2632,9 @@ impl Backend for DockerBackend {
2617
2632
. args ( [ "--name" , & name] )
2618
2633
. arg ( "-i" )
2619
2634
. args ( [ "-a" , "stdin" , "-a" , "stdout" , "-a" , "stderr" ] )
2635
+ // PLAYGROUND_ORCHESTRATOR is vestigial; I'm leaving it
2636
+ // for a bit to allow new containers to get built and
2637
+ // distributed.
2620
2638
. args ( [ "-e" , "PLAYGROUND_ORCHESTRATOR=1" ] )
2621
2639
. arg ( "--rm" )
2622
2640
. arg ( channel. to_container_name ( ) )
@@ -2791,8 +2809,8 @@ mod tests {
2791
2809
project_dir : TempDir ,
2792
2810
}
2793
2811
2794
- impl From < CoordinatorId > for TestBackend {
2795
- fn from ( _id : CoordinatorId ) -> Self {
2812
+ impl From < Arc < dyn IdProvider > > for TestBackend {
2813
+ fn from ( _ids : Arc < dyn IdProvider > ) -> Self {
2796
2814
static COMPILE_WORKER_ONCE : Once = Once :: new ( ) ;
2797
2815
2798
2816
COMPILE_WORKER_ONCE . call_once ( || {
@@ -2846,8 +2864,12 @@ mod tests {
2846
2864
. unwrap_or ( 5 )
2847
2865
} ) ;
2848
2866
2849
- static TEST_COORDINATOR_FACTORY : Lazy < CoordinatorFactory > =
2850
- Lazy :: new ( || CoordinatorFactory :: new ( * MAX_CONCURRENT_TESTS ) ) ;
2867
+ static TEST_COORDINATOR_ID_PROVIDER : Lazy < Arc < GlobalIdProvider > > =
2868
+ Lazy :: new ( || Arc :: new ( GlobalIdProvider :: new ( ) ) ) ;
2869
+
2870
+ static TEST_COORDINATOR_FACTORY : Lazy < CoordinatorFactory > = Lazy :: new ( || {
2871
+ CoordinatorFactory :: new ( TEST_COORDINATOR_ID_PROVIDER . clone ( ) , * MAX_CONCURRENT_TESTS )
2872
+ } ) ;
2851
2873
2852
2874
fn new_coordinator_test ( ) -> Coordinator < TestBackend > {
2853
2875
TEST_COORDINATOR_FACTORY . build ( )
0 commit comments