mirror of
https://github.com/neondatabase/neon.git
synced 2026-01-14 08:52:56 +00:00
## Problem Import up-calls did not enforce the usage of the latest generation. The import might have finished in one previous generation, but not in the latest one. Hence, the controller might try to activate a timeline before it is ready. In theory, that would be fine, but it's tricky to reason about. ## Summary of Changes Pageserver provides the current generation in the upcall to the storage controller and the later validates the generation. If the generation is stale, we return an error which stops progress of the import job. Note that the import job will retry the upcall until the stale location is detached. I'll add some proper tests for this as part of the [checkpointing PR](https://github.com/neondatabase/neon/pull/11862). Closes https://github.com/neondatabase/neon/issues/11884
81 lines
2.3 KiB
Rust
81 lines
2.3 KiB
Rust
//! Types in this file are for pageserver's upward-facing API calls to the storage controller,
|
|
//! required for acquiring and validating tenant generation numbers.
|
|
//!
|
|
//! See docs/rfcs/025-generation-numbers.md
|
|
|
|
use serde::{Deserialize, Serialize};
|
|
use utils::generation::Generation;
|
|
use utils::id::{NodeId, TimelineId};
|
|
|
|
use crate::controller_api::NodeRegisterRequest;
|
|
use crate::models::{LocationConfigMode, ShardImportStatus};
|
|
use crate::shard::TenantShardId;
|
|
|
|
/// Upcall message sent by the pageserver to the configured `control_plane_api` on
|
|
/// startup.
|
|
#[derive(Serialize, Deserialize)]
|
|
pub struct ReAttachRequest {
|
|
pub node_id: NodeId,
|
|
|
|
/// Optional inline self-registration: this is useful with the storage controller,
|
|
/// if the node already has a node_id set.
|
|
#[serde(skip_serializing_if = "Option::is_none", default)]
|
|
pub register: Option<NodeRegisterRequest>,
|
|
}
|
|
|
|
fn default_mode() -> LocationConfigMode {
|
|
LocationConfigMode::AttachedSingle
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug)]
|
|
pub struct ReAttachResponseTenant {
|
|
pub id: TenantShardId,
|
|
/// Mandatory if LocationConfigMode is None or set to an Attached* mode
|
|
pub r#gen: Option<u32>,
|
|
|
|
/// Default value only for backward compat: this field should be set
|
|
#[serde(default = "default_mode")]
|
|
pub mode: LocationConfigMode,
|
|
}
|
|
#[derive(Serialize, Deserialize)]
|
|
pub struct ReAttachResponse {
|
|
pub tenants: Vec<ReAttachResponseTenant>,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize)]
|
|
pub struct ValidateRequestTenant {
|
|
pub id: TenantShardId,
|
|
pub r#gen: u32,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize)]
|
|
pub struct ValidateRequest {
|
|
pub tenants: Vec<ValidateRequestTenant>,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize)]
|
|
pub struct ValidateResponse {
|
|
pub tenants: Vec<ValidateResponseTenant>,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize)]
|
|
pub struct ValidateResponseTenant {
|
|
pub id: TenantShardId,
|
|
pub valid: bool,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize)]
|
|
pub struct TimelineImportStatusRequest {
|
|
pub tenant_shard_id: TenantShardId,
|
|
pub timeline_id: TimelineId,
|
|
pub generation: Generation,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize)]
|
|
pub struct PutTimelineImportStatusRequest {
|
|
pub tenant_shard_id: TenantShardId,
|
|
pub timeline_id: TimelineId,
|
|
pub status: ShardImportStatus,
|
|
pub generation: Generation,
|
|
}
|