Skip to content

Commit 4dec0dd

Browse files
authored
Merge pull request #10447 from neondatabase/releases/2025-01-20-hotfix
Release: storage hotfix 2025-01-20
2 parents 3399eea + e0c504a commit 4dec0dd

File tree

1 file changed

+16
-8
lines changed

1 file changed

+16
-8
lines changed

Diff for: pageserver/src/tenant/timeline/handle.rs

+16-8
Original file line numberDiff line numberDiff line change
@@ -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

611616
impl<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

Comments
 (0)