From 0408f60b58abd0336bcc8aff2016cc0097ca065e Mon Sep 17 00:00:00 2001 From: Thomas Lamprecht Date: Thu, 12 May 2022 11:31:07 +0200 Subject: [PATCH] datastore: add new Lookup for operations tracking We sometimes need to do some in-memory only stuff, e.g., to check if GC is already running for a datastore, which is a try_lock on a mutex that is in-memory. Actually the whole thing would be nicer if we could guarantee to hold the correct contract statically, e.g., like https://docs.rust-embedded.org/book/static-guarantees/design-contracts.html Signed-off-by: Thomas Lamprecht --- pbs-api-types/src/maintenance.rs | 19 ++++++++++++++++++- pbs-datastore/src/datastore.rs | 2 +- pbs-datastore/src/task_tracking.rs | 2 ++ 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/pbs-api-types/src/maintenance.rs b/pbs-api-types/src/maintenance.rs index dd3de50a..2102cf2c 100644 --- a/pbs-api-types/src/maintenance.rs +++ b/pbs-api-types/src/maintenance.rs @@ -20,8 +20,17 @@ pub const MAINTENANCE_MESSAGE_SCHEMA: Schema = #[derive(Clone, Copy, Debug)] /// Operation requirements, used when checking for maintenance mode. pub enum Operation { + /// for any read operation like backup restore or RRD metric collection Read, + /// for any write/delete operation, like backup create or GC Write, + /// for any purely logical operation on the in-memory state of the datastore, e.g., to check if + /// some mutex could be locked (e.g., GC already running?) + /// + /// NOTE: one must *not* do any IO operations when only helding this Op state + Lookup, + + // GarbageCollect or Delete? } #[api] @@ -29,6 +38,12 @@ pub enum Operation { #[serde(rename_all = "kebab-case")] /// Maintenance type. pub enum MaintenanceType { + // TODO: + // - Add "unmounting" once we got pluggable datastores + // - Add "GarbageCollection" or "DeleteOnly" as type and track GC (or all deletes) as separate + // operation, so that one can enable a mode where nothing new can be added but stuff can be + // cleaned + /// Only read operations are allowed on the datastore. ReadOnly, /// Neither read nor write operations are allowed on the datastore. @@ -65,7 +80,9 @@ impl MaintenanceMode { .decode_utf8() .unwrap_or(Cow::Borrowed("")); - if self.ty == MaintenanceType::Offline { + if let Some(Operation::Lookup) = operation { + return Ok(()); + } else if self.ty == MaintenanceType::Offline { bail!("offline maintenance mode: {}", message); } else if self.ty == MaintenanceType::ReadOnly { if let Some(Operation::Write) = operation { diff --git a/pbs-datastore/src/datastore.rs b/pbs-datastore/src/datastore.rs index e2057a00..ddba5b13 100644 --- a/pbs-datastore/src/datastore.rs +++ b/pbs-datastore/src/datastore.rs @@ -133,7 +133,7 @@ impl DataStore { if let Some(maintenance_mode) = config.get_maintenance_mode() { if let Err(error) = maintenance_mode.check(operation) { - bail!("datastore '{}' is in {}", name, error); + bail!("datastore '{name}' is in {error}"); } } diff --git a/pbs-datastore/src/task_tracking.rs b/pbs-datastore/src/task_tracking.rs index c0a419e4..dcb73d9b 100644 --- a/pbs-datastore/src/task_tracking.rs +++ b/pbs-datastore/src/task_tracking.rs @@ -80,6 +80,7 @@ pub fn update_active_operations(name: &str, operation: Operation, count: i64) -> match operation { Operation::Read => task.active_operations.read += count, Operation::Write => task.active_operations.write += count, + Operation::Lookup => (), // no IO must happen there }; } Some(task.clone()) @@ -98,6 +99,7 @@ pub fn update_active_operations(name: &str, operation: Operation, count: i64) -> active_operations: match operation { Operation::Read => ActiveOperationStats { read: 1, write: 0 }, Operation::Write => ActiveOperationStats { read: 0, write: 1 }, + Operation::Lookup => ActiveOperationStats { read: 0, write: 0 }, }, }) }