From abe5523418a7549dc9868acfcfb4c0fcee161178 Mon Sep 17 00:00:00 2001 From: Georgy Moshkin <gmoshkin@picodata.io> Date: Tue, 18 Jul 2023 20:10:52 +0300 Subject: [PATCH] refactor: move schema related property keys handling into a common part --- src/cas.rs | 65 +++++++++++++++++++++++++++++++++++++-------------- src/schema.rs | 11 +-------- 2 files changed, 49 insertions(+), 27 deletions(-) diff --git a/src/cas.rs b/src/cas.rs index 2ee1417979..c0dd0eba99 100644 --- a/src/cas.rs +++ b/src/cas.rs @@ -25,8 +25,6 @@ use tarantool::space::{Space, SpaceId}; use tarantool::tlua; use tarantool::tuple::{KeyDef, ToTupleBuffer, Tuple, TupleBuffer}; -use once_cell::sync::Lazy; - /// This spaces cannot be changed directly dy a [`Dml`] operation. They have /// dedicated operation types (e.g. Ddl, Acl) because updating these spaces /// requires automatically updating corresponding local spaces. @@ -395,20 +393,6 @@ impl Predicate { requested: self.index, conflict_index: entry_index, }; - let ddl_keys: Lazy<Vec<Tuple>> = Lazy::new(|| { - use crate::storage::PropertyName::*; - - [ - PendingSchemaChange.into(), - PendingSchemaVersion.into(), - GlobalSchemaVersion.into(), - NextSchemaVersion.into(), - ] - .into_iter() - .map(|key: &str| Tuple::new(&(key,))) - .collect::<tarantool::Result<_>>() - .expect("keys should convert to tuple") - }); for range in &self.ranges { if modifies_operable(entry_op, range.space, storage) { return Err(error()); @@ -438,7 +422,7 @@ impl Predicate { } Op::DdlPrepare { .. } | Op::DdlCommit | Op::DdlAbort | Op::Acl { .. } => { let key_def = storage.key_def_for_key(space, 0)?; - for key in ddl_keys.iter() { + for key in schema_related_property_keys() { if range.contains(&key_def, key) { return Err(error()); } @@ -451,6 +435,53 @@ impl Predicate { } } +const SCHEMA_RELATED_PROPERTIES: [&str; 4] = [ + crate::storage::PropertyName::PendingSchemaChange.as_str(), + crate::storage::PropertyName::PendingSchemaVersion.as_str(), + crate::storage::PropertyName::GlobalSchemaVersion.as_str(), + crate::storage::PropertyName::NextSchemaVersion.as_str(), +]; + +/// Returns a slice of tuples representing keys of space _pico_property which +/// should be used to check predicates of schema changing CaS operations. +fn schema_related_property_keys() -> &'static [Tuple] { + static mut DATA: Option<Vec<Tuple>> = None; + + // Safety: we only call this from tx thread, so it's ok, trust me + unsafe { + if DATA.is_none() { + let mut data = Vec::with_capacity(SCHEMA_RELATED_PROPERTIES.len()); + for key in SCHEMA_RELATED_PROPERTIES { + let t = Tuple::new(&(key,)).expect("keys should convert to tuple"); + data.push(t); + } + DATA = Some(data); + } + + DATA.as_ref().unwrap() + } +} + +/// Returns a slice of [`Range`] structs which are needed for the CaS +/// request which performs a schema change operation. +pub fn schema_change_ranges() -> &'static [Range] { + static mut DATA: Option<Vec<Range>> = None; + + // Safety: we only call this from tx thread, so it's ok, trust me + unsafe { + if DATA.is_none() { + let mut data = Vec::with_capacity(SCHEMA_RELATED_PROPERTIES.len()); + for key in SCHEMA_RELATED_PROPERTIES { + let r = Range::new(ClusterwideSpaceId::Property).eq((key,)); + data.push(r); + } + DATA = Some(data); + } + + DATA.as_ref().unwrap() + } +} + /// Represents a lua table describing a [`Range`]. /// /// This is only used to parse lua arguments from lua api functions such as diff --git a/src/schema.rs b/src/schema.rs index f588320717..8ed1cb6ea0 100644 --- a/src/schema.rs +++ b/src/schema.rs @@ -631,16 +631,7 @@ pub fn prepare_schema_change(op: Op, timeout: Duration) -> traft::Result<RaftInd let predicate = cas::Predicate { index, term, - ranges: vec![ - cas::Range::new(ClusterwideSpaceId::Property) - .eq((PropertyName::PendingSchemaChange,)), - cas::Range::new(ClusterwideSpaceId::Property) - .eq((PropertyName::PendingSchemaVersion,)), - cas::Range::new(ClusterwideSpaceId::Property) - .eq((PropertyName::GlobalSchemaVersion,)), - cas::Range::new(ClusterwideSpaceId::Property) - .eq((PropertyName::NextSchemaVersion,)), - ], + ranges: cas::schema_change_ranges().into(), }; let (index, term) = compare_and_swap(op, predicate, timeout)?; node.wait_index(index, timeout)?; -- GitLab