@@ -60,12 +60,12 @@ impl<K: Eq + Hash, V> InFlightOwnerGuard<'_, K, V> {
6060 . entry
6161 . result
6262 . lock ( )
63- . expect ( "locator cache in-flight result lock poisoned" ) = Some ( result) ;
63+ . unwrap_or_else ( |poisoned| poisoned. into_inner ( ) ) = Some ( result) ;
6464
6565 if let Some ( key) = self . key . take ( ) {
6666 self . in_flight
6767 . lock ( )
68- . expect ( "locator cache in-flight lock poisoned" )
68+ . unwrap_or_else ( |poisoned| poisoned. into_inner ( ) )
6969 . remove ( & key) ;
7070 }
7171
@@ -212,12 +212,12 @@ impl<K: Eq + Hash, V: Clone> LocatorCache<K, V> {
212212 let mut result = entry
213213 . result
214214 . lock ( )
215- . expect ( "locator cache in-flight result lock poisoned" ) ;
215+ . unwrap_or_else ( |poisoned| poisoned. into_inner ( ) ) ;
216216 while result. is_none ( ) {
217217 result = entry
218218 . changed
219219 . wait ( result)
220- . expect ( "locator cache in-flight condvar poisoned" ) ;
220+ . unwrap_or_else ( |poisoned| poisoned. into_inner ( ) ) ;
221221 }
222222
223223 result. clone ( ) . unwrap ( )
@@ -414,6 +414,49 @@ mod tests {
414414 ) ;
415415 }
416416
417+ #[ test]
418+ fn test_cache_publish_result_recovers_poisoned_in_flight_locks ( ) {
419+ let key = "key" . to_string ( ) ;
420+ let entry = Arc :: new ( InFlightEntry :: new ( ) ) ;
421+ let in_flight: Arc < Mutex < HashMap < String , Arc < InFlightEntry < i32 > > > > > =
422+ Arc :: new ( Mutex :: new ( HashMap :: new ( ) ) ) ;
423+
424+ in_flight. lock ( ) . unwrap ( ) . insert ( key. clone ( ) , entry. clone ( ) ) ;
425+
426+ let poison_entry = entry. clone ( ) ;
427+ assert ! ( thread:: spawn( move || {
428+ let _guard = poison_entry. result. lock( ) . unwrap( ) ;
429+ panic!( "poison result lock" ) ;
430+ } )
431+ . join( )
432+ . is_err( ) ) ;
433+
434+ let poison_in_flight = in_flight. clone ( ) ;
435+ assert ! ( thread:: spawn( move || {
436+ let _guard = poison_in_flight. lock( ) . unwrap( ) ;
437+ panic!( "poison in-flight lock" ) ;
438+ } )
439+ . join( )
440+ . is_err( ) ) ;
441+
442+ let owner = InFlightOwnerGuard {
443+ key : Some ( key) ,
444+ entry : entry. clone ( ) ,
445+ in_flight : & in_flight,
446+ } ;
447+
448+ owner. complete ( Some ( 42 ) ) ;
449+
450+ assert_eq ! (
451+ LocatorCache :: <String , i32 >:: wait_for_in_flight( entry) ,
452+ Some ( 42 )
453+ ) ;
454+ assert ! ( in_flight
455+ . lock( )
456+ . unwrap_or_else( |poisoned| poisoned. into_inner( ) )
457+ . is_empty( ) ) ;
458+ }
459+
417460 #[ test]
418461 fn test_cache_clear ( ) {
419462 let cache: LocatorCache < String , i32 > = LocatorCache :: new ( ) ;
0 commit comments