@@ -588,32 +588,40 @@ impl<T: Types> Drop for Cache<T> {
588588 let Some ( handle_inner_arc) = handle_inner_weak. upgrade ( ) else {
589589 continue ;
590590 } ;
591- let handle_timeline = handle_inner_arc
591+ let Some ( handle_timeline) = handle_inner_arc
592592 // locking rules: drop lock before acquiring other lock below
593593 . lock ( )
594594 . expect ( "poisoned" )
595- . shutdown ( ) ;
595+ . shutdown ( )
596+ else {
597+ // Concurrent PerTimelineState::shutdown.
598+ continue ;
599+ } ;
600+ // Clean up per_timeline_state so the HandleInner allocation can be dropped.
596601 let per_timeline_state = handle_timeline. per_timeline_state ( ) ;
597602 let mut handles_lock_guard = per_timeline_state. handles . lock ( ) . expect ( "mutex poisoned" ) ;
598603 let Some ( handles) = & mut * handles_lock_guard else {
599604 continue ;
600605 } ;
601606 let Some ( removed_handle_inner_arc) = handles. remove ( & self . id ) else {
602- // There could have been a shutdown inbetween us upgrading the weak and locking the mutex .
607+ // Concurrent PerTimelineState:: shutdown.
603608 continue ;
604609 } ;
605- drop ( handles_lock_guard) ; // locking rules: remember them when !
606- assert ! ( Arc :: ptr_eq( & removed_handle_inner_arc, & handle_inner_arc, ) ) ;
610+ drop ( handles_lock_guard) ; // locking rules!
611+ assert ! ( Arc :: ptr_eq( & removed_handle_inner_arc, & handle_inner_arc) ) ;
607612 }
608613 }
609614}
610615
611616impl < T : Types > HandleInner < T > {
612- fn shutdown ( & mut self ) -> Arc < T :: Timeline > {
617+ fn shutdown ( & mut self ) -> Option < Arc < T :: Timeline > > {
613618 match std:: mem:: replace ( self , HandleInner :: ShutDown ) {
614- HandleInner :: KeepingTimelineGateOpen { timeline, .. } => timeline,
619+ HandleInner :: KeepingTimelineGateOpen { timeline, .. } => Some ( timeline) ,
615620 HandleInner :: ShutDown => {
616- unreachable ! ( "handles are only shut down once in their lifetime" ) ;
621+ // Duplicate shutdowns are possible because both Cache::drop and PerTimelineState::shutdown
622+ // may do it concurrently, but locking rules disallow holding per-timeline-state lock and
623+ // the handle lock at the same time.
624+ None
617625 }
618626 }
619627 }
0 commit comments