@@ -11,11 +11,7 @@ use std::collections::HashMap;
1111use std:: fs;
1212use std:: io:: { ErrorKind , Read , Write } ;
1313use std:: path:: { Path , PathBuf } ;
14- #[ cfg( test) ]
15- use std:: sync:: atomic:: AtomicBool ;
1614use std:: sync:: atomic:: { AtomicU64 , AtomicUsize , Ordering } ;
17- #[ cfg( test) ]
18- use std:: sync:: mpsc;
1915use std:: sync:: { Arc , Mutex , RwLock } ;
2016
2117#[ cfg( target_os = "windows" ) ]
@@ -95,20 +91,14 @@ impl FilesystemStoreState {
9591 }
9692
9793 fn get_new_version_and_lock_ref ( & self , dest_file_path : PathBuf ) -> ( Arc < RwLock < u64 > > , u64 ) {
98- let mut outer_lock = self . inner . locks . lock ( ) . unwrap ( ) ;
99-
100- // Allocate the version while holding the lock map mutex so that clean_locks cannot remove the entry after a
101- // version has been reserved but before its lock reference is cloned.
10294 let version = self . next_version . fetch_add ( 1 , Ordering :: Relaxed ) ;
10395 if version == u64:: MAX {
10496 panic ! ( "FilesystemStore version counter overflowed" ) ;
10597 }
106- #[ cfg( test) ]
107- maybe_pause_after_version_allocation ( & self . inner , & dest_file_path) ;
10898
10999 // Get a reference to the inner lock. We do this early so that the arc can double as an in-flight counter for
110100 // cleaning up unused locks.
111- let inner_lock_ref = Arc :: clone ( & outer_lock . entry ( dest_file_path ) . or_default ( ) ) ;
101+ let inner_lock_ref = self . inner . get_inner_lock_ref ( dest_file_path ) ;
112102
113103 ( inner_lock_ref, version)
114104 }
@@ -861,79 +851,3 @@ pub(crate) fn get_key_from_dir_entry_path(
861851 } ,
862852 }
863853}
864-
865- #[ cfg( test) ]
866- struct VersionAllocatedHook {
867- dest_file_path : PathBuf ,
868- version_allocated : mpsc:: Sender < ( ) > ,
869- continue_write : Mutex < mpsc:: Receiver < ( ) > > ,
870- fired : AtomicBool ,
871- }
872-
873- #[ cfg( test) ]
874- static VERSION_ALLOCATED_HOOK : Mutex < Option < Arc < VersionAllocatedHook > > > = Mutex :: new ( None ) ;
875-
876- #[ cfg( test) ]
877- fn maybe_pause_after_version_allocation ( inner : & FilesystemStoreInner , dest_file_path : & Path ) {
878- let hook = VERSION_ALLOCATED_HOOK . lock ( ) . unwrap ( ) . clone ( ) ;
879- if let Some ( hook) = hook {
880- if hook. dest_file_path . as_path ( ) != dest_file_path
881- || hook. fired . swap ( true , Ordering :: AcqRel )
882- {
883- return ;
884- }
885-
886- let version_allocation_holds_lock = inner. locks . try_lock ( ) . is_err ( ) ;
887- hook. version_allocated . send ( ( ) ) . unwrap ( ) ;
888- if !version_allocation_holds_lock {
889- hook. continue_write . lock ( ) . unwrap ( ) . recv ( ) . unwrap ( ) ;
890- }
891- }
892- }
893-
894- #[ cfg( test) ]
895- mod tests {
896- use super :: * ;
897-
898- use std:: sync:: Arc ;
899- use std:: thread;
900-
901- #[ test]
902- fn stale_write_after_lock_cleanup_does_not_overwrite_newer_write ( ) {
903- let mut temp_path = std:: env:: temp_dir ( ) ;
904- temp_path. push ( "test_stale_write_after_lock_cleanup" ) ;
905- let _ = std:: fs:: remove_dir_all ( & temp_path) ;
906-
907- let state = Arc :: new ( FilesystemStoreState :: new ( temp_path. clone ( ) ) ) ;
908- let path =
909- state. get_checked_dest_file_path ( "ns" , "sub" , Some ( "key" ) , "write" , false ) . unwrap ( ) ;
910- let ( version_allocated, wait_for_version) = mpsc:: channel ( ) ;
911- let ( continue_write, wait_to_continue) = mpsc:: channel ( ) ;
912- * VERSION_ALLOCATED_HOOK . lock ( ) . unwrap ( ) = Some ( Arc :: new ( VersionAllocatedHook {
913- dest_file_path : path. clone ( ) ,
914- version_allocated,
915- continue_write : Mutex :: new ( wait_to_continue) ,
916- fired : AtomicBool :: new ( false ) ,
917- } ) ) ;
918-
919- let state_for_thread = Arc :: clone ( & state) ;
920- let path_for_thread = path. clone ( ) ;
921- let stale_write = thread:: spawn ( move || {
922- let ( inner_lock_ref, version) =
923- state_for_thread. get_new_version_and_lock_ref ( path_for_thread. clone ( ) ) ;
924- state_for_thread
925- . inner
926- . write_version ( inner_lock_ref, path_for_thread, b"stale" . to_vec ( ) , version, false )
927- . unwrap ( ) ;
928- } ) ;
929-
930- wait_for_version. recv ( ) . unwrap ( ) ;
931- state. write_impl ( "ns" , "sub" , "key" , b"newer" . to_vec ( ) , false ) . unwrap ( ) ;
932- continue_write. send ( ( ) ) . unwrap ( ) ;
933- stale_write. join ( ) . unwrap ( ) ;
934- * VERSION_ALLOCATED_HOOK . lock ( ) . unwrap ( ) = None ;
935-
936- assert_eq ! ( state. read_impl( "ns" , "sub" , "key" , false ) . unwrap( ) , b"newer" ) ;
937- let _ = std:: fs:: remove_dir_all ( temp_path) ;
938- }
939- }
0 commit comments