LCOV - code coverage report
Current view: top level - libs/pageserver_api/src - controller_api.rs (source / functions) Coverage Total Hit
Test: 02e8c57acd6e2b986849f552ca30280d54699b79.info Lines: 26.9 % 67 18
Test Date: 2024-06-26 17:13:54 Functions: 3.1 % 226 7

            Line data    Source code
       1              : use std::str::FromStr;
       2              : 
       3              : /// Request/response types for the storage controller
       4              : /// API (`/control/v1` prefix).  Implemented by the server
       5              : /// in [`storage_controller::http`]
       6              : use serde::{Deserialize, Serialize};
       7              : use utils::id::{NodeId, TenantId};
       8              : 
       9              : use crate::{
      10              :     models::{ShardParameters, TenantConfig},
      11              :     shard::{ShardStripeSize, TenantShardId},
      12              : };
      13              : 
      14            0 : #[derive(Serialize, Deserialize)]
      15              : pub struct TenantCreateResponseShard {
      16              :     pub shard_id: TenantShardId,
      17              :     pub node_id: NodeId,
      18              :     pub generation: u32,
      19              : }
      20              : 
      21            0 : #[derive(Serialize, Deserialize)]
      22              : pub struct TenantCreateResponse {
      23              :     pub shards: Vec<TenantCreateResponseShard>,
      24              : }
      25              : 
      26            0 : #[derive(Serialize, Deserialize)]
      27              : pub struct NodeRegisterRequest {
      28              :     pub node_id: NodeId,
      29              : 
      30              :     pub listen_pg_addr: String,
      31              :     pub listen_pg_port: u16,
      32              : 
      33              :     pub listen_http_addr: String,
      34              :     pub listen_http_port: u16,
      35              : }
      36              : 
      37            0 : #[derive(Serialize, Deserialize)]
      38              : pub struct NodeConfigureRequest {
      39              :     pub node_id: NodeId,
      40              : 
      41              :     pub availability: Option<NodeAvailabilityWrapper>,
      42              :     pub scheduling: Option<NodeSchedulingPolicy>,
      43              : }
      44              : 
      45            0 : #[derive(Serialize, Deserialize)]
      46              : pub struct TenantPolicyRequest {
      47              :     pub placement: Option<PlacementPolicy>,
      48              :     pub scheduling: Option<ShardSchedulingPolicy>,
      49              : }
      50              : 
      51            0 : #[derive(Serialize, Deserialize, Debug)]
      52              : pub struct TenantLocateResponseShard {
      53              :     pub shard_id: TenantShardId,
      54              :     pub node_id: NodeId,
      55              : 
      56              :     pub listen_pg_addr: String,
      57              :     pub listen_pg_port: u16,
      58              : 
      59              :     pub listen_http_addr: String,
      60              :     pub listen_http_port: u16,
      61              : }
      62              : 
      63            0 : #[derive(Serialize, Deserialize)]
      64              : pub struct TenantLocateResponse {
      65              :     pub shards: Vec<TenantLocateResponseShard>,
      66              :     pub shard_params: ShardParameters,
      67              : }
      68              : 
      69            0 : #[derive(Serialize, Deserialize)]
      70              : pub struct TenantDescribeResponse {
      71              :     pub tenant_id: TenantId,
      72              :     pub shards: Vec<TenantDescribeResponseShard>,
      73              :     pub stripe_size: ShardStripeSize,
      74              :     pub policy: PlacementPolicy,
      75              :     pub config: TenantConfig,
      76              : }
      77              : 
      78            0 : #[derive(Serialize, Deserialize)]
      79              : pub struct NodeDescribeResponse {
      80              :     pub id: NodeId,
      81              : 
      82              :     pub availability: NodeAvailabilityWrapper,
      83              :     pub scheduling: NodeSchedulingPolicy,
      84              : 
      85              :     pub listen_http_addr: String,
      86              :     pub listen_http_port: u16,
      87              : 
      88              :     pub listen_pg_addr: String,
      89              :     pub listen_pg_port: u16,
      90              : }
      91              : 
      92            0 : #[derive(Serialize, Deserialize)]
      93              : pub struct TenantDescribeResponseShard {
      94              :     pub tenant_shard_id: TenantShardId,
      95              : 
      96              :     pub node_attached: Option<NodeId>,
      97              :     pub node_secondary: Vec<NodeId>,
      98              : 
      99              :     pub last_error: String,
     100              : 
     101              :     /// A task is currently running to reconcile this tenant's intent state with the state on pageservers
     102              :     pub is_reconciling: bool,
     103              :     /// This shard failed in sending a compute notification to the cloud control plane, and a retry is pending.
     104              :     pub is_pending_compute_notification: bool,
     105              :     /// A shard split is currently underway
     106              :     pub is_splitting: bool,
     107              : 
     108              :     pub scheduling_policy: ShardSchedulingPolicy,
     109              : }
     110              : 
     111              : /// Explicitly migrating a particular shard is a low level operation
     112              : /// TODO: higher level "Reschedule tenant" operation where the request
     113              : /// specifies some constraints, e.g. asking it to get off particular node(s)
     114            0 : #[derive(Serialize, Deserialize, Debug)]
     115              : pub struct TenantShardMigrateRequest {
     116              :     pub tenant_shard_id: TenantShardId,
     117              :     pub node_id: NodeId,
     118              : }
     119              : 
     120              : /// Utilisation score indicating how good a candidate a pageserver
     121              : /// is for scheduling the next tenant. See [`crate::models::PageserverUtilization`].
     122              : /// Lower values are better.
     123            0 : #[derive(Serialize, Deserialize, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Debug)]
     124              : pub struct UtilizationScore(pub u64);
     125              : 
     126              : impl UtilizationScore {
     127           44 :     pub fn worst() -> Self {
     128           44 :         UtilizationScore(u64::MAX)
     129           44 :     }
     130              : }
     131              : 
     132            0 : #[derive(Serialize, Deserialize, Clone, Copy, Debug)]
     133              : #[serde(into = "NodeAvailabilityWrapper")]
     134              : pub enum NodeAvailability {
     135              :     // Normal, happy state
     136              :     Active(UtilizationScore),
     137              :     // Offline: Tenants shouldn't try to attach here, but they may assume that their
     138              :     // secondary locations on this node still exist.  Newly added nodes are in this
     139              :     // state until we successfully contact them.
     140              :     Offline,
     141              : }
     142              : 
     143              : impl PartialEq for NodeAvailability {
     144            0 :     fn eq(&self, other: &Self) -> bool {
     145              :         use NodeAvailability::*;
     146            0 :         matches!((self, other), (Active(_), Active(_)) | (Offline, Offline))
     147            0 :     }
     148              : }
     149              : 
     150              : impl Eq for NodeAvailability {}
     151              : 
     152              : // This wrapper provides serde functionality and it should only be used to
     153              : // communicate with external callers which don't know or care about the
     154              : // utilisation score of the pageserver it is targeting.
     155            0 : #[derive(Serialize, Deserialize, Clone, Copy, Debug)]
     156              : pub enum NodeAvailabilityWrapper {
     157              :     Active,
     158              :     Offline,
     159              : }
     160              : 
     161              : impl From<NodeAvailabilityWrapper> for NodeAvailability {
     162            0 :     fn from(val: NodeAvailabilityWrapper) -> Self {
     163            0 :         match val {
     164              :             // Assume the worst utilisation score to begin with. It will later be updated by
     165              :             // the heartbeats.
     166            0 :             NodeAvailabilityWrapper::Active => NodeAvailability::Active(UtilizationScore::worst()),
     167            0 :             NodeAvailabilityWrapper::Offline => NodeAvailability::Offline,
     168              :         }
     169            0 :     }
     170              : }
     171              : 
     172              : impl From<NodeAvailability> for NodeAvailabilityWrapper {
     173            0 :     fn from(val: NodeAvailability) -> Self {
     174            0 :         match val {
     175            0 :             NodeAvailability::Active(_) => NodeAvailabilityWrapper::Active,
     176            0 :             NodeAvailability::Offline => NodeAvailabilityWrapper::Offline,
     177              :         }
     178            0 :     }
     179              : }
     180              : 
     181            0 : #[derive(Serialize, Deserialize, Clone, Copy, Eq, PartialEq, Debug)]
     182              : pub enum ShardSchedulingPolicy {
     183              :     // Normal mode: the tenant's scheduled locations may be updated at will, including
     184              :     // for non-essential optimization.
     185              :     Active,
     186              : 
     187              :     // Disable optimizations, but permit scheduling when necessary to fulfil the PlacementPolicy.
     188              :     // For example, this still permits a node's attachment location to change to a secondary in
     189              :     // response to a node failure, or to assign a new secondary if a node was removed.
     190              :     Essential,
     191              : 
     192              :     // No scheduling: leave the shard running wherever it currently is.  Even if the shard is
     193              :     // unavailable, it will not be rescheduled to another node.
     194              :     Pause,
     195              : 
     196              :     // No reconciling: we will make no location_conf API calls to pageservers at all.  If the
     197              :     // shard is unavailable, it stays that way.  If a node fails, this shard doesn't get failed over.
     198              :     Stop,
     199              : }
     200              : 
     201              : impl Default for ShardSchedulingPolicy {
     202           22 :     fn default() -> Self {
     203           22 :         Self::Active
     204           22 :     }
     205              : }
     206              : 
     207            0 : #[derive(Serialize, Deserialize, Clone, Copy, Eq, PartialEq, Debug)]
     208              : pub enum NodeSchedulingPolicy {
     209              :     Active,
     210              :     Filling,
     211              :     Pause,
     212              :     PauseForRestart,
     213              :     Draining,
     214              : }
     215              : 
     216              : impl FromStr for NodeSchedulingPolicy {
     217              :     type Err = anyhow::Error;
     218              : 
     219            0 :     fn from_str(s: &str) -> Result<Self, Self::Err> {
     220            0 :         match s {
     221            0 :             "active" => Ok(Self::Active),
     222            0 :             "filling" => Ok(Self::Filling),
     223            0 :             "pause" => Ok(Self::Pause),
     224            0 :             "pause_for_restart" => Ok(Self::PauseForRestart),
     225            0 :             "draining" => Ok(Self::Draining),
     226            0 :             _ => Err(anyhow::anyhow!("Unknown scheduling state '{s}'")),
     227              :         }
     228            0 :     }
     229              : }
     230              : 
     231              : impl From<NodeSchedulingPolicy> for String {
     232            0 :     fn from(value: NodeSchedulingPolicy) -> String {
     233            0 :         use NodeSchedulingPolicy::*;
     234            0 :         match value {
     235            0 :             Active => "active",
     236            0 :             Filling => "filling",
     237            0 :             Pause => "pause",
     238            0 :             PauseForRestart => "pause_for_restart",
     239            0 :             Draining => "draining",
     240              :         }
     241            0 :         .to_string()
     242            0 :     }
     243              : }
     244              : 
     245              : /// Controls how tenant shards are mapped to locations on pageservers, e.g. whether
     246              : /// to create secondary locations.
     247            8 : #[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq)]
     248              : pub enum PlacementPolicy {
     249              :     /// Normal live state: one attached pageserver and zero or more secondaries.
     250              :     Attached(usize),
     251              :     /// Create one secondary mode locations. This is useful when onboarding
     252              :     /// a tenant, or for an idle tenant that we might want to bring online quickly.
     253              :     Secondary,
     254              : 
     255              :     /// Do not attach to any pageservers.  This is appropriate for tenants that
     256              :     /// have been idle for a long time, where we do not mind some delay in making
     257              :     /// them available in future.
     258              :     Detached,
     259              : }
     260              : 
     261            0 : #[derive(Serialize, Deserialize, Debug)]
     262              : pub struct TenantShardMigrateResponse {}
     263              : 
     264              : #[cfg(test)]
     265              : mod test {
     266              :     use super::*;
     267              :     use serde_json;
     268              : 
     269              :     /// Check stability of PlacementPolicy's serialization
     270              :     #[test]
     271            2 :     fn placement_policy_encoding() -> anyhow::Result<()> {
     272            2 :         let v = PlacementPolicy::Attached(1);
     273            2 :         let encoded = serde_json::to_string(&v)?;
     274            2 :         assert_eq!(encoded, "{\"Attached\":1}");
     275            2 :         assert_eq!(serde_json::from_str::<PlacementPolicy>(&encoded)?, v);
     276              : 
     277            2 :         let v = PlacementPolicy::Detached;
     278            2 :         let encoded = serde_json::to_string(&v)?;
     279            2 :         assert_eq!(encoded, "\"Detached\"");
     280            2 :         assert_eq!(serde_json::from_str::<PlacementPolicy>(&encoded)?, v);
     281            2 :         Ok(())
     282            2 :     }
     283              : }
        

Generated by: LCOV version 2.1-beta