From a72af29d12314fe132a91a0d2a8e1fe56fec7878 Mon Sep 17 00:00:00 2001 From: John Spray Date: Wed, 24 Jan 2024 11:49:30 +0000 Subject: [PATCH] control_plane/attachment_service: implement PlacementPolicy::Detached (#6458) ## Problem The API for detaching things wasn't implement yet, but one could hit this case indirectly from tests when using attach-hook, and find tenants unexpectedly attached again because their policy remained Single. ## Summary of changes Add PlacementPolicy::Detached, and: - add the behavior for it in schedule() - in tenant_migrate, refuse if the policy is detached - automatically set this policy in attach-hook if the caller has specified pageserver=null. --- control_plane/attachment_service/src/lib.rs | 2 ++ control_plane/attachment_service/src/persistence.rs | 1 + control_plane/attachment_service/src/service.rs | 12 +++++++++++- control_plane/attachment_service/src/tenant_state.rs | 12 ++++++++++++ 4 files changed, 26 insertions(+), 1 deletion(-) diff --git a/control_plane/attachment_service/src/lib.rs b/control_plane/attachment_service/src/lib.rs index d8f996952a..e4ca9aa304 100644 --- a/control_plane/attachment_service/src/lib.rs +++ b/control_plane/attachment_service/src/lib.rs @@ -17,6 +17,8 @@ enum PlacementPolicy { /// Production-ready way to attach a tenant: one attached pageserver and /// some number of secondaries. Double(usize), + /// Do not attach to any pageservers + Detached, } #[derive(Ord, PartialOrd, Eq, PartialEq, Copy, Clone)] diff --git a/control_plane/attachment_service/src/persistence.rs b/control_plane/attachment_service/src/persistence.rs index 4a3fc8c779..e944a2e9ed 100644 --- a/control_plane/attachment_service/src/persistence.rs +++ b/control_plane/attachment_service/src/persistence.rs @@ -245,6 +245,7 @@ impl Persistence { anyhow::bail!("Tried to increment generation of unknown shard"); }; shard.generation_pageserver = None; + shard.placement_policy = serde_json::to_string(&PlacementPolicy::Detached).unwrap(); Ok(()) }) .await diff --git a/control_plane/attachment_service/src/service.rs b/control_plane/attachment_service/src/service.rs index 5b44c097b1..c9ed07ae5f 100644 --- a/control_plane/attachment_service/src/service.rs +++ b/control_plane/attachment_service/src/service.rs @@ -381,6 +381,11 @@ impl Service { if let Some(new_generation) = new_generation { tenant_state.generation = new_generation; + } else { + // This is a detach notification. We must update placement policy to avoid re-attaching + // during background scheduling/reconciliation, or during attachment service restart. + assert!(attach_req.node_id.is_none()); + tenant_state.policy = PlacementPolicy::Detached; } if let Some(attaching_pageserver) = attach_req.node_id.as_ref() { @@ -870,7 +875,6 @@ impl Service { } else { let old_attached = shard.intent.attached; - shard.intent.attached = Some(migrate_req.node_id); match shard.policy { PlacementPolicy::Single => { shard.intent.secondary.clear(); @@ -884,7 +888,13 @@ impl Service { shard.intent.secondary.push(old_attached); } } + PlacementPolicy::Detached => { + return Err(ApiError::BadRequest(anyhow::anyhow!( + "Cannot migrate a tenant that is PlacementPolicy::Detached: configure it to an attached policy first" + ))) + } } + shard.intent.attached = Some(migrate_req.node_id); tracing::info!("Migrating: new intent {:?}", shard.intent); shard.sequence = shard.sequence.next(); diff --git a/control_plane/attachment_service/src/tenant_state.rs b/control_plane/attachment_service/src/tenant_state.rs index a907628eff..5290197d84 100644 --- a/control_plane/attachment_service/src/tenant_state.rs +++ b/control_plane/attachment_service/src/tenant_state.rs @@ -312,6 +312,18 @@ impl TenantState { modified = true; } } + Detached => { + // Should have no attached or secondary pageservers + if self.intent.attached.is_some() { + self.intent.attached = None; + modified = true; + } + + if !self.intent.secondary.is_empty() { + self.intent.secondary.clear(); + modified = true; + } + } } if modified {