diff --git a/compute_tools/src/compute.rs b/compute_tools/src/compute.rs index d678b7d670..16bcf4a81f 100644 --- a/compute_tools/src/compute.rs +++ b/compute_tools/src/compute.rs @@ -3,7 +3,7 @@ use chrono::{DateTime, Utc}; use compute_api::privilege::Privilege; use compute_api::responses::{ ComputeConfig, ComputeCtlConfig, ComputeMetrics, ComputeStatus, LfcOffloadState, - LfcPrewarmState, + LfcPrewarmState, PromoteState }; use compute_api::spec::{ ComputeAudit, ComputeFeature, ComputeMode, ComputeSpec, ExtVersion, PgIdent, @@ -161,6 +161,8 @@ pub struct ComputeState { pub lfc_prewarm_state: LfcPrewarmState, pub lfc_offload_state: LfcOffloadState, + pub promote_state: PromoteState, + pub metrics: ComputeMetrics, } diff --git a/compute_tools/src/compute_promote.rs b/compute_tools/src/compute_promote.rs new file mode 100644 index 0000000000..96cf9a3126 --- /dev/null +++ b/compute_tools/src/compute_promote.rs @@ -0,0 +1,26 @@ +use compute_api::responses::{LfcOffloadState, PromoteState}; + +use crate::compute::ComputeNode; + +impl ComputeNode { + pub async fn promote(&self) -> PromoteState { + { + let state = &mut self.state.lock().unwrap().promote_state; + if let PromoteState::Promoting = + std::mem::replace(state, PromoteState::Promoting) + { + return state; + } + } + + // reference:: configure + // 1. Check if we're not primary + // 4. Check we have safekeepers list supplied from primary + // 2. Check we have prewarmed LFC + // 3. Wait for last LSN to be committed + // 4. Call pg_promote + if !matches!(self.lfc_offload_state(), LfcOffloadState::Completed) { + } + } +} + diff --git a/compute_tools/src/http/routes/lfc.rs b/compute_tools/src/http/routes/lfc.rs index 07bcc6bfb7..6c6c4e9244 100644 --- a/compute_tools/src/http/routes/lfc.rs +++ b/compute_tools/src/http/routes/lfc.rs @@ -10,7 +10,7 @@ pub(in crate::http) async fn prewarm_state(compute: Compute) -> Json Json { Json(compute.lfc_offload_state()) diff --git a/compute_tools/src/http/routes/mod.rs b/compute_tools/src/http/routes/mod.rs index 432e66a830..90f2615655 100644 --- a/compute_tools/src/http/routes/mod.rs +++ b/compute_tools/src/http/routes/mod.rs @@ -12,6 +12,7 @@ pub(in crate::http) mod failpoints; pub(in crate::http) mod grants; pub(in crate::http) mod insights; pub(in crate::http) mod lfc; +pub(in crate::http) mod promote; pub(in crate::http) mod metrics; pub(in crate::http) mod metrics_json; pub(in crate::http) mod status; diff --git a/compute_tools/src/http/routes/promote.rs b/compute_tools/src/http/routes/promote.rs new file mode 100644 index 0000000000..ef8a41f583 --- /dev/null +++ b/compute_tools/src/http/routes/promote.rs @@ -0,0 +1,17 @@ +use axum::response::Response; +use compute_api::responses::PromoteState; +use http::StatusCode; + +use crate::http::JsonResponse; +type Compute = axum::extract::State>; + +/// Returns only when promote failes or succeeds. +/// If a network error occurs, this does not stop promotion, and subsequent +/// calls block until first error or success +pub(in crate::http) async fn promote(compute: Compute) -> Response { + let state = compute.promote().await; + if let PromoteState::Failed { error } = state { + return JsonResponse::error(StatusCode::INTERNAL_SERVER_ERROR, error); + } + JsonResponse::success(StatusCode::OK, state) +} diff --git a/compute_tools/src/http/server.rs b/compute_tools/src/http/server.rs index d5d2427971..17939e39d4 100644 --- a/compute_tools/src/http/server.rs +++ b/compute_tools/src/http/server.rs @@ -23,7 +23,7 @@ use super::{ middleware::authorize::Authorize, routes::{ check_writability, configure, database_schema, dbs_and_roles, extension_server, extensions, - grants, insights, lfc, metrics, metrics_json, status, terminate, + grants, insights, lfc, metrics, metrics_json, promote, status, terminate, }, }; use crate::compute::ComputeNode; @@ -87,6 +87,7 @@ impl From<&Server> for Router> { let authenticated_router = Router::>::new() .route("/lfc/prewarm", get(lfc::prewarm_state).post(lfc::prewarm)) .route("/lfc/offload", get(lfc::offload_state).post(lfc::offload)) + .route("/promote", post(promote::promote)) .route("/check_writability", post(check_writability::is_writable)) .route("/configure", post(configure::configure)) .route("/database_schema", get(database_schema::get_schema_dump)) diff --git a/compute_tools/src/lib.rs b/compute_tools/src/lib.rs index 7218067a8a..d2935cc809 100644 --- a/compute_tools/src/lib.rs +++ b/compute_tools/src/lib.rs @@ -12,6 +12,7 @@ pub mod logger; pub mod catalog; pub mod compute; pub mod compute_prewarm; +pub mod compute_promote; pub mod disk_quota; pub mod extension_server; pub mod installed_extensions; diff --git a/libs/compute_api/src/responses.rs b/libs/compute_api/src/responses.rs index 24d371c6eb..18b7b730dc 100644 --- a/libs/compute_api/src/responses.rs +++ b/libs/compute_api/src/responses.rs @@ -70,6 +70,18 @@ pub enum LfcOffloadState { }, } +#[derive(Serialize, Default, Debug, Clone)] +#[serde(tag = "status", rename_all = "snake_case")] +pub enum PromoteState { + #[default] + NotPromoted, + Promoting, + Completed, + Failed { + error: String, + }, +} + /// Response of the /status API #[derive(Serialize, Debug, Deserialize)] #[serde(rename_all = "snake_case")]