From 6f5baf69b56f4dfdf51bbb22730943c4ab5f8eff Mon Sep 17 00:00:00 2001 From: o0Ignition0o <jeremy.lempereur@gmail.com> Date: Tue, 13 Apr 2021 09:58:39 +0200 Subject: [PATCH 1/6] wip --- src/bastion/Cargo.toml | 1 + src/bastion/src/system/global_state.rs | 13 ++++++------- src/bastion/src/system/mod.rs | 6 ++---- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/bastion/Cargo.toml b/src/bastion/Cargo.toml index 3cdae511..f1eda889 100644 --- a/src/bastion/Cargo.toml +++ b/src/bastion/Cargo.toml @@ -55,5 +55,6 @@ lever = "0.1.1-alpha.11" lightproc = "0.3.5" regex = "1.3.9" uuid = { version = "0.8", features = ["v4"] } +once_cell = "1.7.2" [dev-dependencies] diff --git a/src/bastion/src/system/global_state.rs b/src/bastion/src/system/global_state.rs index 1bac489a..5853933f 100644 --- a/src/bastion/src/system/global_state.rs +++ b/src/bastion/src/system/global_state.rs @@ -19,7 +19,7 @@ pub struct GlobalState { #[derive(Debug, Clone)] /// A container for user-defined types. -struct GlobalDataContainer(Arc<AtomicBox<Box<dyn Any>>>); +struct GlobalDataContainer(Arc<dyn Any + Send + Sync>); impl GlobalState { /// Returns a new instance of global state. @@ -40,10 +40,10 @@ impl GlobalState { } /// Returns the requested data type to the caller. - pub fn read<'a, T: Send + Sync + 'static>(&mut self) -> Option<&'a T> { + pub fn read<T: Send + Sync + 'static>(&mut self) -> Option<Arc<T>> { self.table - .get(&TypeId::of::<T>()) - .and_then(|container| container.read::<T>()) + .get(&TypeId::of::<Arc<T>>()) + .and_then(|gdc| gdc.read()) } /// Checks the given values is storing in the global state. @@ -65,9 +65,8 @@ impl GlobalDataContainer { GlobalDataContainer(Arc::new(AtomicBox::new(Box::new(value)))) } - pub fn read<'a, T: Send + Sync + 'static>(&self) -> Option<&'a T> { - let inner = self.0.get(); - inner.downcast_ref::<T>() + pub fn read<T: Send + Sync + 'static>(&self) -> Option<Arc<T>> { + self.0.downcast_ref::<Arc<T>>().map(Arc::clone) } } diff --git a/src/bastion/src/system/mod.rs b/src/bastion/src/system/mod.rs index 94786d64..c9934e48 100644 --- a/src/bastion/src/system/mod.rs +++ b/src/bastion/src/system/mod.rs @@ -1,10 +1,8 @@ mod global_state; mod node; -use lazy_static::lazy_static; +use once_cell::sync::Lazy; use crate::system::node::Node; -lazy_static! { - pub static ref SYSTEM: Node = Node::new(); -} +pub static SYSTEM: Lazy<Node> = Lazy::new(Node::new); From 0bf4a5eb6e486464fdebb4970d76571639dea0c6 Mon Sep 17 00:00:00 2001 From: o0Ignition0o <jeremy.lempereur@gmail.com> Date: Tue, 13 Apr 2021 12:31:31 +0200 Subject: [PATCH 2/6] wip --- src/bastion/src/system/global_state.rs | 96 ++++++++++++++++++++------ 1 file changed, 75 insertions(+), 21 deletions(-) diff --git a/src/bastion/src/system/global_state.rs b/src/bastion/src/system/global_state.rs index 5853933f..cfdf0217 100644 --- a/src/bastion/src/system/global_state.rs +++ b/src/bastion/src/system/global_state.rs @@ -14,13 +14,9 @@ use crate::error::{BastionError, Result}; #[derive(Debug)] pub struct GlobalState { - table: LOTable<TypeId, GlobalDataContainer>, + table: LOTable<TypeId, Arc<dyn Any + Send + Sync>>, } -#[derive(Debug, Clone)] -/// A container for user-defined types. -struct GlobalDataContainer(Arc<dyn Any + Send + Sync>); - impl GlobalState { /// Returns a new instance of global state. pub(crate) fn new() -> Self { @@ -32,18 +28,37 @@ impl GlobalState { /// Inserts the given value in the global state. If the value /// exists, it will be overridden. pub fn insert<T: Send + Sync + 'static>(&mut self, value: T) -> bool { - let container = GlobalDataContainer::new(value); self.table - .insert(TypeId::of::<T>(), container) + .insert( + TypeId::of::<T>(), + Arc::new(value) as Arc<dyn Any + Send + Sync>, + ) .ok() .is_some() } - /// Returns the requested data type to the caller. - pub fn read<T: Send + Sync + 'static>(&mut self) -> Option<Arc<T>> { + /// Invokes a function with the requested data type. + pub fn read<T: Send + Sync + 'static>(&mut self, f: impl FnOnce(Option<&T>)) { + self.table + .get(&TypeId::of::<T>()) + .map(|value| f(value.downcast_ref())); + } + + /// Invokes a function with the requested data type. + pub fn write<T: std::fmt::Debug + Send + Sync + 'static, F>(&mut self, f: F) -> Option<Arc<T>> + where + F: Fn(Option<Arc<T>>) -> Option<Arc<T>>, + { self.table - .get(&TypeId::of::<Arc<T>>()) - .and_then(|gdc| gdc.read()) + .replace_with(&TypeId::of::<T>(), |maybe_as_any| { + dbg!((&*(maybe_as_any.unwrap())).type_id(), TypeId::of::<T>()); + let maybe_as_t = maybe_as_any.and_then(|v| v.downcast_ref::<Arc<T>>()); + let maybe_output = f(maybe_as_t.map(|arc_t| Arc::clone(&arc_t))); + + let maybe_as_any = maybe_output.map(|t| Arc::new(t) as Arc<dyn Any + Send + Sync>); + maybe_as_any + }) + .and_then(|as_any| as_any.downcast_ref::<Arc<T>>().map(|t| Arc::clone(&t))) } /// Checks the given values is storing in the global state. @@ -60,16 +75,6 @@ impl GlobalState { } } -impl GlobalDataContainer { - pub fn new<T: Send + Sync + 'static>(value: T) -> Self { - GlobalDataContainer(Arc::new(AtomicBox::new(Box::new(value)))) - } - - pub fn read<T: Send + Sync + 'static>(&self) -> Option<Arc<T>> { - self.0.downcast_ref::<Arc<T>>().map(Arc::clone) - } -} - #[cfg(test)] mod tests { use crate::system::global_state::GlobalState; @@ -135,4 +140,53 @@ mod tests { let is_removed = instance.remove::<usize>(); assert_eq!(is_removed, false); } + + #[test] + fn test_write_read() { + let mut instance = GlobalState::new(); + + #[derive(Debug, PartialEq, Clone)] + struct Hello { + foo: bool, + bar: usize, + } + use core::any::TypeId; + use std::sync::Arc; + dbg!( + TypeId::of::<Hello>(), + TypeId::of::<Arc<Hello>>(), + TypeId::of::<std::any::Any>(), + TypeId::of::<Option<Arc<Hello>>>(), + ); + + let expected = Hello { foo: true, bar: 42 }; + + instance.insert(expected.clone()); + + instance.read(|actual: Option<&Hello>| { + assert_eq!(&expected, actual.unwrap()); + }); + + let expected_updated = Hello { + foo: false, + bar: 43, + }; + + let actual_updated = instance.write::<Hello, _>(|maybe_to_update| { + let to_update = maybe_to_update.unwrap(); + + let updated = Hello { + foo: false, + bar: 43, + }; + Some(std::sync::Arc::new(updated)) + }); + + assert_eq!(&expected_updated, &*actual_updated.unwrap()); + + instance.read(|updated: Option<&Hello>| { + let updated = updated.unwrap(); + assert_eq!(&expected_updated, updated); + }); + } } From 62c057246a8715e96ac450824aecc869780d4e54 Mon Sep 17 00:00:00 2001 From: o0Ignition0o <jeremy.lempereur@gmail.com> Date: Tue, 13 Apr 2021 13:08:32 +0200 Subject: [PATCH 3/6] wip --- src/bastion/src/system/global_state.rs | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/bastion/src/system/global_state.rs b/src/bastion/src/system/global_state.rs index cfdf0217..1c55cf40 100644 --- a/src/bastion/src/system/global_state.rs +++ b/src/bastion/src/system/global_state.rs @@ -45,20 +45,20 @@ impl GlobalState { } /// Invokes a function with the requested data type. - pub fn write<T: std::fmt::Debug + Send + Sync + 'static, F>(&mut self, f: F) -> Option<Arc<T>> + pub fn write<T: std::fmt::Debug + Send + Sync + 'static, F>(&mut self, f: F) -> Option<&T> where - F: Fn(Option<Arc<T>>) -> Option<Arc<T>>, + F: Fn(Option<&T>) -> Option<T>, { self.table .replace_with(&TypeId::of::<T>(), |maybe_as_any| { - dbg!((&*(maybe_as_any.unwrap())).type_id(), TypeId::of::<T>()); - let maybe_as_t = maybe_as_any.and_then(|v| v.downcast_ref::<Arc<T>>()); - let maybe_output = f(maybe_as_t.map(|arc_t| Arc::clone(&arc_t))); + let maybe_output = f(maybe_as_any.and_then(|v| (*v).downcast_ref::<T>())); + + dbg!(&maybe_output); let maybe_as_any = maybe_output.map(|t| Arc::new(t) as Arc<dyn Any + Send + Sync>); maybe_as_any }) - .and_then(|as_any| as_any.downcast_ref::<Arc<T>>().map(|t| Arc::clone(&t))) + .and_then(|as_any| as_any.downcast_ref::<T>()) } /// Checks the given values is storing in the global state. @@ -176,10 +176,11 @@ mod tests { let to_update = maybe_to_update.unwrap(); let updated = Hello { - foo: false, - bar: 43, + foo: !to_update.foo, + bar: to_update.bar + 1, }; - Some(std::sync::Arc::new(updated)) + + Some(updated) }); assert_eq!(&expected_updated, &*actual_updated.unwrap()); From c609f65e491627459c8fa7cbb124bc59208a887a Mon Sep 17 00:00:00 2001 From: o0Ignition0o <jeremy.lempereur@gmail.com> Date: Tue, 13 Apr 2021 13:32:56 +0200 Subject: [PATCH 4/6] wip --- src/bastion/src/system/global_state.rs | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/src/bastion/src/system/global_state.rs b/src/bastion/src/system/global_state.rs index 1c55cf40..3c1ad239 100644 --- a/src/bastion/src/system/global_state.rs +++ b/src/bastion/src/system/global_state.rs @@ -45,20 +45,16 @@ impl GlobalState { } /// Invokes a function with the requested data type. - pub fn write<T: std::fmt::Debug + Send + Sync + 'static, F>(&mut self, f: F) -> Option<&T> + pub fn write<T: std::fmt::Debug + Send + Sync + 'static, F>(&mut self, f: F) where F: Fn(Option<&T>) -> Option<T>, { - self.table - .replace_with(&TypeId::of::<T>(), |maybe_as_any| { - let maybe_output = f(maybe_as_any.and_then(|v| (*v).downcast_ref::<T>())); - - dbg!(&maybe_output); - - let maybe_as_any = maybe_output.map(|t| Arc::new(t) as Arc<dyn Any + Send + Sync>); - maybe_as_any - }) - .and_then(|as_any| as_any.downcast_ref::<T>()) + self.table.replace_with(&TypeId::of::<T>(), |maybe_as_any| { + match f(maybe_as_any.and_then(|v| (*v).downcast_ref::<T>())) { + Some(output) => Some(Arc::new(output) as Arc<dyn Any + Send + Sync>), + None => None, + } + }); } /// Checks the given values is storing in the global state. @@ -172,7 +168,7 @@ mod tests { bar: 43, }; - let actual_updated = instance.write::<Hello, _>(|maybe_to_update| { + instance.write::<Hello, _>(|maybe_to_update| { let to_update = maybe_to_update.unwrap(); let updated = Hello { @@ -183,11 +179,9 @@ mod tests { Some(updated) }); - assert_eq!(&expected_updated, &*actual_updated.unwrap()); - instance.read(|updated: Option<&Hello>| { let updated = updated.unwrap(); - assert_eq!(&expected_updated, updated); + assert_eq!(updated, &expected_updated); }); } } From 81940b8ca23faeeef3536ee5b0e271340a79d35d Mon Sep 17 00:00:00 2001 From: o0Ignition0o <jeremy.lempereur@gmail.com> Date: Tue, 13 Apr 2021 14:14:02 +0200 Subject: [PATCH 5/6] remove debug statements --- src/bastion/src/system/global_state.rs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/bastion/src/system/global_state.rs b/src/bastion/src/system/global_state.rs index 3c1ad239..06fcce5a 100644 --- a/src/bastion/src/system/global_state.rs +++ b/src/bastion/src/system/global_state.rs @@ -146,14 +146,6 @@ mod tests { foo: bool, bar: usize, } - use core::any::TypeId; - use std::sync::Arc; - dbg!( - TypeId::of::<Hello>(), - TypeId::of::<Arc<Hello>>(), - TypeId::of::<std::any::Any>(), - TypeId::of::<Option<Arc<Hello>>>(), - ); let expected = Hello { foo: true, bar: 42 }; From d2993d809d59295a5449a749e66a742dcb0fc75a Mon Sep 17 00:00:00 2001 From: o0Ignition0o <jeremy.lempereur@gmail.com> Date: Tue, 13 Apr 2021 21:16:31 +0200 Subject: [PATCH 6/6] ok it doesnt get any uglier than this but it runs --- src/bastion/src/system/global_state.rs | 51 +++++++++++++++++--------- 1 file changed, 34 insertions(+), 17 deletions(-) diff --git a/src/bastion/src/system/global_state.rs b/src/bastion/src/system/global_state.rs index 06fcce5a..9ee1d40c 100644 --- a/src/bastion/src/system/global_state.rs +++ b/src/bastion/src/system/global_state.rs @@ -1,27 +1,32 @@ +use std::sync::Arc; /// This module contains implementation of the global state that /// available to all actors in runtime. To provide safety and avoid /// data races, the implementation is heavily relies on software /// transaction memory (or shortly STM) mechanisms to eliminate any /// potential data races and provide consistency across actors. -use std::any::{Any, TypeId}; -use std::ops::Deref; -use std::sync::Arc; +use std::{ + any::{Any, TypeId}, + sync::RwLock, +}; +use std::{collections::hash_map::Entry, ops::Deref}; use lever::sync::atomics::AtomicBox; use lever::table::lotable::LOTable; +use lightproc::proc_state::AsAny; +use std::collections::HashMap; use crate::error::{BastionError, Result}; #[derive(Debug)] pub struct GlobalState { - table: LOTable<TypeId, Arc<dyn Any + Send + Sync>>, + table: Arc<RwLock<HashMap<TypeId, Arc<dyn Any + Send + Sync>>>>, // todo: remove the arc<rwlock< once we figure it out } impl GlobalState { /// Returns a new instance of global state. pub(crate) fn new() -> Self { GlobalState { - table: LOTable::new(), + table: Arc::new(RwLock::new(HashMap::new())), } } @@ -29,17 +34,20 @@ impl GlobalState { /// exists, it will be overridden. pub fn insert<T: Send + Sync + 'static>(&mut self, value: T) -> bool { self.table + .write() + .unwrap() .insert( TypeId::of::<T>(), Arc::new(value) as Arc<dyn Any + Send + Sync>, ) - .ok() .is_some() } /// Invokes a function with the requested data type. pub fn read<T: Send + Sync + 'static>(&mut self, f: impl FnOnce(Option<&T>)) { self.table + .read() + .unwrap() .get(&TypeId::of::<T>()) .map(|value| f(value.downcast_ref())); } @@ -49,25 +57,34 @@ impl GlobalState { where F: Fn(Option<&T>) -> Option<T>, { - self.table.replace_with(&TypeId::of::<T>(), |maybe_as_any| { - match f(maybe_as_any.and_then(|v| (*v).downcast_ref::<T>())) { - Some(output) => Some(Arc::new(output) as Arc<dyn Any + Send + Sync>), - None => None, - } - }); + let mut hm = self.table.write().unwrap(); + let stuff_to_insert = match hm.entry(TypeId::of::<T>()) { + Entry::Occupied(data) => f(data.get().downcast_ref()), + Entry::Vacant(_) => f(None), + }; + + if let Some(stuff) = stuff_to_insert { + hm.insert( + TypeId::of::<T>(), + Arc::new(stuff) as Arc<dyn Any + Send + Sync>, + ); + } else { + hm.remove(&TypeId::of::<T>()); + }; } /// Checks the given values is storing in the global state. pub fn contains<T: Send + Sync + 'static>(&self) -> bool { - self.table.contains_key(&TypeId::of::<T>()) + self.table.read().unwrap().contains_key(&TypeId::of::<T>()) } /// Deletes the entry from the global state. pub fn remove<T: Send + Sync + 'static>(&mut self) -> bool { - match self.table.remove(&TypeId::of::<T>()) { - Ok(entry) => entry.is_some(), - Err(_) => false, - } + self.table + .write() + .unwrap() + .remove(&TypeId::of::<T>()) + .is_some() } }