Skip to content
This repository was archived by the owner on May 9, 2022. It is now read-only.

Commit 8da78d5

Browse files
committed
feat(rtc_tenclave,kv_store): add key-value store module
This contains in-memory implementations and a property test, so far.
1 parent c6d137d commit 8da78d5

File tree

5 files changed

+174
-0
lines changed

5 files changed

+174
-0
lines changed
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
//! In-memory implementations of [`KvStore`] (for testing)
2+
3+
use serde::de::DeserializeOwned;
4+
use serde::Serialize;
5+
use std::collections::HashMap;
6+
use std::prelude::v1::*;
7+
8+
use super::{KvStore, StoreResult};
9+
10+
/// In-memory [`KvStore`] using [`HashMap`]
11+
#[derive(Default)]
12+
pub struct InMemoryStore<V> {
13+
pub(crate) map: HashMap<String, V>,
14+
}
15+
16+
impl<V> KvStore<V> for InMemoryStore<V>
17+
where
18+
V: Clone,
19+
{
20+
fn load(&self, key: &str) -> StoreResult<Option<V>> {
21+
Ok(self.map.get(key).cloned())
22+
}
23+
24+
fn save(&mut self, key: &str, value: V) -> StoreResult<()> {
25+
self.map.insert(key.to_string(), value);
26+
Ok(())
27+
}
28+
}
29+
30+
/// In-memory [`KvStore`] using [`HashMap`] and [`serde_json`] serialization
31+
#[derive(Default)]
32+
pub struct InMemoryJsonStore {
33+
pub(crate) map: HashMap<String, Vec<u8>>,
34+
}
35+
36+
impl<V> KvStore<V> for InMemoryJsonStore
37+
where
38+
V: Serialize + DeserializeOwned,
39+
{
40+
fn load(&self, key: &str) -> StoreResult<Option<V>> {
41+
let loaded: Option<&[u8]> = self.map.get(key).map(|v| v.as_slice());
42+
let deserialized: Option<V> = loaded.map(serde_json::from_slice).transpose()?;
43+
Ok(deserialized)
44+
}
45+
46+
fn save(&mut self, key: &str, value: V) -> StoreResult<()> {
47+
let serialized = serde_json::to_vec(&value)?;
48+
self.map.insert(key.to_string(), serialized);
49+
Ok(())
50+
}
51+
}

rtc_tenclave/src/kv_store/inspect.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
//! Support for inspecting [`KvStore`] instances (for testing and debugging)
2+
3+
use serde::de::DeserializeOwned;
4+
use serde::Serialize;
5+
use std::borrow::ToOwned;
6+
use std::collections::HashMap;
7+
use std::iter::Iterator;
8+
9+
use super::in_memory::{InMemoryJsonStore, InMemoryStore};
10+
use super::KvStore;
11+
12+
pub trait InspectStore<V> {
13+
fn as_map(&self) -> HashMap<String, V>;
14+
}
15+
16+
impl<V> InspectStore<V> for InMemoryStore<V>
17+
where
18+
V: Clone,
19+
{
20+
fn as_map(&self) -> HashMap<String, V> {
21+
self.map.clone()
22+
}
23+
}
24+
25+
impl<V> InspectStore<V> for InMemoryJsonStore
26+
where
27+
V: Serialize + DeserializeOwned,
28+
{
29+
fn as_map(&self) -> HashMap<String, V> {
30+
self.map
31+
.keys()
32+
.map(|k| {
33+
let loaded: Option<V> = self.load(&k).expect(&format!("load {:?} failed!", k));
34+
let v: V = loaded.expect(&format!("key missing! {:?}", k));
35+
(k.to_owned(), v)
36+
})
37+
.collect()
38+
}
39+
}

rtc_tenclave/src/kv_store/mod.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
//! Simple key-value store abstraction
2+
3+
use std::boxed::Box;
4+
use std::error::Error;
5+
6+
type StoreResult<T> = Result<T, Box<dyn Error>>;
7+
8+
/// A key-value store.
9+
///
10+
/// These methods borrow key references, and
11+
///
12+
pub trait KvStore<V> {
13+
// TODO: Use associated type for V?
14+
15+
/// Load the saved value for `key`, if any.
16+
///
17+
/// Return [`None`] if `key` has no previous value.
18+
///
19+
fn load(&self, key: &str) -> StoreResult<Option<V>>;
20+
21+
/// Save a new value for `key`.
22+
///
23+
/// This will replace any existing value.
24+
///
25+
fn save(&mut self, key: &str, value: V) -> StoreResult<()>;
26+
27+
// TODO: add update()
28+
}
29+
30+
#[cfg(test)]
31+
mod in_memory;
32+
33+
#[cfg(test)]
34+
mod inspect;
35+
36+
#[cfg(test)]
37+
mod tests;

rtc_tenclave/src/kv_store/tests.rs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
//! Tests for [`rtc_tenclave::kv_store`]
2+
3+
use std::collections::HashMap;
4+
5+
use proptest::prelude::*;
6+
7+
use super::in_memory::{InMemoryJsonStore, InMemoryStore};
8+
use super::inspect::InspectStore;
9+
use super::KvStore;
10+
11+
/// Verify that executing a sequence of store operations matches a simple model.
12+
#[test]
13+
fn prop_store_ops_match_model() {
14+
// Strategy to generate store operations: currently, just key / value pairs to save.
15+
let store_ops_strategy = {
16+
let keys = prop_oneof!(r"[a-z]{0,5}", ".*");
17+
let values = prop_oneof!(keys.clone()); // TODO: Non-string values
18+
19+
// This strategy will generate key / value pairs with multiple values per key,
20+
// and shuffle them to have some interleaving, for bugs that depend on that.
21+
proptest::collection::hash_map(keys, proptest::collection::vec(values, 0..10), 0..10)
22+
.prop_map(flatten_key_values)
23+
.prop_shuffle()
24+
};
25+
26+
proptest!(|(store_ops_vec in store_ops_strategy)| {
27+
type V = String;
28+
let mut store_model: InMemoryStore<V> = InMemoryStore::default();
29+
let mut store_model_json: InMemoryJsonStore = InMemoryJsonStore::default();
30+
// TODO: FS-based store
31+
32+
for (k, v) in store_ops_vec {
33+
store_model.save(&k, v.clone()).expect("InMemoryStore save failed!");
34+
store_model_json.save(&k, v.clone()).expect("InMemoryJsonStore save failed!");
35+
36+
prop_assert_eq!(store_model.as_map(), store_model_json.as_map());
37+
}
38+
});
39+
}
40+
41+
/// Helper: Flatten `{K => [V, …], …}` to `[(K, V), …]`, cloning `K` for each `V`.
42+
fn flatten_key_values<K: Clone, V>(kvs: HashMap<K, Vec<V>>) -> Vec<(K, V)> {
43+
kvs.into_iter()
44+
.flat_map(|(k, vs)| vs.into_iter().map(move |v| (k.clone(), v)))
45+
.collect()
46+
}

rtc_tenclave/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,5 @@ cfg_if::cfg_if! {
2323

2424
pub mod crypto;
2525
pub mod enclave;
26+
pub mod kv_store;
2627
pub mod util;

0 commit comments

Comments
 (0)