From 700d92952955f5ad3dbf87657dd4d39f63d889b7 Mon Sep 17 00:00:00 2001 From: Dmitry Rodionov Date: Wed, 26 Jul 2023 14:05:18 +0300 Subject: [PATCH] Init Timeline in Stopping state in create_timeline_struct when Cause::Delete (#4780) See https://github.com/neondatabase/neon/pull/4552#discussion_r1258368127 for context. TLDR: use CreateTimelineCause to infer desired state instead of using .set_stopping after initialization --- pageserver/src/tenant.rs | 26 +++++++++++++++++--------- pageserver/src/tenant/delete.rs | 5 ++--- pageserver/src/tenant/timeline.rs | 3 ++- 3 files changed, 21 insertions(+), 13 deletions(-) diff --git a/pageserver/src/tenant.rs b/pageserver/src/tenant.rs index 67447bc45c..8f13055cc1 100644 --- a/pageserver/src/tenant.rs +++ b/pageserver/src/tenant.rs @@ -2012,19 +2012,24 @@ impl Tenant { init_order: Option<&InitializationOrder>, cause: CreateTimelineCause, ) -> anyhow::Result> { - if matches!(cause, CreateTimelineCause::Load) { - let ancestor_id = new_metadata.ancestor_timeline(); - anyhow::ensure!( - ancestor_id == ancestor.as_ref().map(|t| t.timeline_id), - "Timeline's {new_timeline_id} ancestor {ancestor_id:?} was not found" - ); - } + let state = match cause { + CreateTimelineCause::Load => { + let ancestor_id = new_metadata.ancestor_timeline(); + anyhow::ensure!( + ancestor_id == ancestor.as_ref().map(|t| t.timeline_id), + "Timeline's {new_timeline_id} ancestor {ancestor_id:?} was not found" + ); + TimelineState::Loading + } + CreateTimelineCause::Delete => TimelineState::Stopping, + }; let initial_logical_size_can_start = init_order.map(|x| &x.initial_logical_size_can_start); let initial_logical_size_attempt = init_order.map(|x| &x.initial_logical_size_attempt); let pg_version = new_metadata.pg_version(); - Ok(Timeline::new( + + let timeline = Timeline::new( self.conf, Arc::clone(&self.tenant_conf), new_metadata, @@ -2036,7 +2041,10 @@ impl Tenant { pg_version, initial_logical_size_can_start.cloned(), initial_logical_size_attempt.cloned(), - )) + state, + ); + + Ok(timeline) } fn new( diff --git a/pageserver/src/tenant/delete.rs b/pageserver/src/tenant/delete.rs index 02d1c997a3..eeaaf15c32 100644 --- a/pageserver/src/tenant/delete.rs +++ b/pageserver/src/tenant/delete.rs @@ -403,6 +403,8 @@ impl DeleteTimelineFlow { remote_client: Option, init_order: Option<&InitializationOrder>, ) -> anyhow::Result<()> { + // Note: here we even skip populating layer map. Timeline is essentially uninitialized. + // RemoteTimelineClient is the only functioning part. let timeline = tenant .create_timeline_struct( timeline_id, @@ -422,9 +424,6 @@ impl DeleteTimelineFlow { .expect("cannot happen because we're the only owner"), ); - // Note: here we even skip populating layer map. Timeline is essentially uninitialized. - // RemoteTimelineClient is the only functioning part. - timeline.set_state(TimelineState::Stopping); // We meed to do this because when console retries delete request we shouldnt answer with 404 // because 404 means successful deletion. { diff --git a/pageserver/src/tenant/timeline.rs b/pageserver/src/tenant/timeline.rs index af9edbf95e..1002595909 100644 --- a/pageserver/src/tenant/timeline.rs +++ b/pageserver/src/tenant/timeline.rs @@ -1360,9 +1360,10 @@ impl Timeline { pg_version: u32, initial_logical_size_can_start: Option, initial_logical_size_attempt: Option, + state: TimelineState, ) -> Arc { let disk_consistent_lsn = metadata.disk_consistent_lsn(); - let (state, _) = watch::channel(TimelineState::Loading); + let (state, _) = watch::channel(state); let (layer_flush_start_tx, _) = tokio::sync::watch::channel(0); let (layer_flush_done_tx, _) = tokio::sync::watch::channel((0, Ok(())));