diff --git a/server/src/coredb/array.rs b/server/src/coredb/array.rs index 81409c48..3e25e556 100644 --- a/server/src/coredb/array.rs +++ b/server/src/coredb/array.rs @@ -105,6 +105,24 @@ impl Array { init_len: 0, } } + /// This literally turns [T; M] into [T; N]. How can you expect it to be safe? + /// This function is extremely unsafe. I mean, I don't even know how to call it safe. + /// There's one way though: make M == N. This will panic in debug mode if M > N. In + /// release mode, good luck + pub unsafe fn from_const_array(arr: [T; M]) -> Self { + debug_assert!( + N > M, + "Provided const array exceeds size limit of initialized array" + ); + // do not double-free or destroy the elements + let array = ManuallyDrop::new(arr); + let mut arr = Array::::new(); + // copy it over + let ptr = &*array as *const [T; M] as *const [MaybeUninit; N]; + ptr.copy_to_nonoverlapping(&mut arr.stack as *mut [MaybeUninit; N], 1); + arr.set_len(N); + arr + } /// Get the apparent length of the array pub const fn len(&self) -> usize { self.init_len as usize @@ -238,6 +256,15 @@ impl Array { } } } + /// Extend self from a slice + /// + /// ## Safety + /// The same danger as in from_slice_unchecked + pub unsafe fn from_slice(slice_ref: impl AsRef<[T]>) -> Self { + let mut slf = Self::new(); + slf.extend_from_slice_unchecked(slice_ref.as_ref()); + slf + } // these operations are incredibly safe because we only pass the initialized part // of the array /// Get self as a slice. Super safe because we guarantee that all the other invarians @@ -266,16 +293,7 @@ impl ops::DerefMut for Array { impl From<[T; N]> for Array { fn from(array: [T; N]) -> Self { - // do not double-free or destroy the elements - let array = ManuallyDrop::new(array); - let mut arr = Array::::new(); - unsafe { - // copy it over - let ptr = &*array as *const [T; N] as *const [MaybeUninit; N]; - ptr.copy_to_nonoverlapping(&mut arr.stack as *mut [MaybeUninit; N], 1); - arr.set_len(N); - } - arr + unsafe { Array::from_const_array::(array) } } } @@ -557,7 +575,7 @@ macro_rules! array_from_string { } #[test] -fn test_map_serialize() { +fn test_map_serialize_deserialize() { use crate::coredb::htable::Coremap; let map = Coremap::new(); map.true_if_insert( @@ -569,3 +587,17 @@ fn test_map_serialize() { assert!(bc.len() == map.len()); assert!(bc.into_iter().all(|(k, _v)| { map.contains_key(&k) })); } + +#[test] +#[should_panic] +fn test_array_overflow() { + let mut arr: Array = Array::new(); + arr.extend_from_slice("123456".as_bytes()).unwrap(); +} + +#[test] +#[should_panic] +fn test_array_overflow_iter() { + let mut arr: Array = Array::new(); + arr.extend("123456".chars()); +} diff --git a/server/src/coredb/memstore.rs b/server/src/coredb/memstore.rs index 073e8f10..952d6cfc 100644 --- a/server/src/coredb/memstore.rs +++ b/server/src/coredb/memstore.rs @@ -56,6 +56,7 @@ #![allow(dead_code)] // TODO(@ohsayan): Remove this onece we're done +use crate::coredb::array::Array; use crate::coredb::htable::Coremap; use crate::coredb::htable::Data; use crate::coredb::SnapshotStatus; @@ -63,6 +64,16 @@ use crate::kvengine::KVEngine; use std::sync::atomic::AtomicBool; use std::sync::Arc; +const DEFAULT_ARRAY: [u8; 7] = [b'd', b'e', b'f', b'a', b'u', b'l', b't']; +/// typedef for the namespace/keyspace IDs. We don't need too much fancy here, +/// no atomic pointers and all. Just a nice array. With amazing gurantees +type NsKsTblId = Array; +macro_rules! defaultid { + () => {{ + unsafe { Array::from_const_array(DEFAULT_ARRAY) } + }}; +} + mod cluster { /// This is for the future where every node will be allocated a shard #[derive(Debug)] @@ -105,7 +116,7 @@ pub enum DdlError { /// for connection-level control abilities over the namespace pub struct Memstore { /// the namespaces - namespaces: Arc>>, + namespaces: Arc>>, } impl Memstore { @@ -134,19 +145,22 @@ impl Memstore { Self { namespaces: { let n = Coremap::new(); - n.true_if_insert(Data::from("default"), Arc::new(Namespace::empty_default())); + n.true_if_insert(defaultid!(), Arc::new(Namespace::empty_default())); Arc::new(n) }, } } /// Get an atomic reference to a namespace - pub fn get_namespace_atomic_ref(&self, namespace_identifier: Data) -> Option> { + pub fn get_namespace_atomic_ref( + &self, + namespace_identifier: NsKsTblId, + ) -> Option> { self.namespaces .get(&namespace_identifier) .map(|ns| ns.clone()) } /// Returns true if a new namespace was created - pub fn create_namespace(&self, namespace_identifier: Data) -> bool { + pub fn create_namespace(&self, namespace_identifier: NsKsTblId) -> bool { self.namespaces .true_if_insert(namespace_identifier, Arc::new(Namespace::empty())) } @@ -156,7 +170,7 @@ impl Memstore { /// Namespaces hold keyspaces pub struct Namespace { /// the keyspaces stored in this namespace - keyspaces: Coremap>, + keyspaces: Coremap>, /// the shard range shard_range: cluster::ClusterShardRange, } @@ -180,24 +194,24 @@ impl Namespace { Self { keyspaces: { let ks = Coremap::new(); - ks.true_if_insert(Data::from("default"), Arc::new(Keyspace::empty_default())); + ks.true_if_insert(defaultid!(), Arc::new(Keyspace::empty_default())); ks }, shard_range: cluster::ClusterShardRange::default(), } } /// Get an atomic reference to a keyspace, if it exists - pub fn get_keyspace_atomic_ref(&self, keyspace_idenitifer: Data) -> Option> { + pub fn get_keyspace_atomic_ref(&self, keyspace_idenitifer: NsKsTblId) -> Option> { self.keyspaces.get(&keyspace_idenitifer).map(|v| v.clone()) } /// Create a new keyspace if it doesn't exist - pub fn create_keyspace(&self, keyspace_idenitifer: Data) -> bool { + pub fn create_keyspace(&self, keyspace_idenitifer: NsKsTblId) -> bool { self.keyspaces .true_if_insert(keyspace_idenitifer, Arc::new(Keyspace::empty())) } /// Drop a keyspace if it is not in use **and** it is empty and not the default - pub fn drop_keyspace(&self, keyspace_idenitifer: Data) -> Result<(), DdlError> { - if keyspace_idenitifer.eq(&Data::from("default")) { + pub fn drop_keyspace(&self, keyspace_idenitifer: NsKsTblId) -> Result<(), DdlError> { + if keyspace_idenitifer.eq(&defaultid!()) { // can't delete default keyspace Err(DdlError::ProtectedObject) } else if self.keyspaces.contains_key(&keyspace_idenitifer) {