Skip to content

Commit

Permalink
runtime/storage/mkvs: Add method for checking local key existence
Browse files Browse the repository at this point in the history
  • Loading branch information
jberci committed Jun 1, 2020
1 parent ae6de84 commit fb20be9
Show file tree
Hide file tree
Showing 11 changed files with 171 additions and 13 deletions.
4 changes: 4 additions & 0 deletions .changelog/2938.feature.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
runtime/storage/mkvs: Add method for checking local key existence

Adds a method to probe the local cache for key existence, guaranteeing
that no remote syncing will be done.
4 changes: 4 additions & 0 deletions client/src/transaction/snapshot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,10 @@ impl MKVS for BlockSnapshot {
MKVS::get(&self.mkvs, ctx, key)
}

fn cache_contains_key(&self, ctx: Context, key: &[u8]) -> bool {
MKVS::cache_contains_key(&self.mkvs, ctx, key)
}

fn insert(&mut self, _ctx: Context, _key: &[u8], _value: &[u8]) -> Option<Vec<u8>> {
unimplemented!("block snapshot is read-only");
}
Expand Down
4 changes: 3 additions & 1 deletion runtime/src/storage/mkvs/cache/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,13 @@ pub trait Cache {
/// Dereference a node pointer into a concrete node object.
///
/// Calling this method may invoke the underlying read syncer.
/// Giving a None fetcher forces the dereference to be local-only,
/// without invoking the read syncer.
fn deref_node_ptr<F: ReadSyncFetcher>(
&mut self,
ctx: &Arc<Context>,
ptr: NodePtrRef,
fetcher: F,
fetcher: Option<F>,
) -> Fallible<Option<NodeRef>>;
/// Perform a remote sync with the configured remote syncer.
fn remote_sync<F: ReadSyncFetcher>(
Expand Down
10 changes: 8 additions & 2 deletions runtime/src/storage/mkvs/cache/lru_cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -415,7 +415,7 @@ impl Cache for LRUCache {
&mut self,
ctx: &Arc<Context>,
ptr: NodePtrRef,
fetcher: F,
fetcher: Option<F>,
) -> Fallible<Option<NodeRef>> {
let ptr_ref = ptr;
let ptr = ptr_ref.borrow();
Expand Down Expand Up @@ -447,7 +447,13 @@ impl Cache for LRUCache {
}

// Node not available locally, fetch from read syncer.
self.remote_sync(ctx, ptr_ref.clone(), fetcher)?;
if let Some(fetcher) = fetcher {
self.remote_sync(ctx, ptr_ref.clone(), fetcher)?;
} else {
return Err(format_err!(
"mkvs: node to dereference not available locally and no fetcher provided"
));
}

let ptr = ptr_ref.borrow();
if ptr.node.is_none() {
Expand Down
7 changes: 7 additions & 0 deletions runtime/src/storage/mkvs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,13 @@ pub trait MKVS: Send + Sync {
/// Fetch entry with given key.
fn get(&self, ctx: Context, key: &[u8]) -> Option<Vec<u8>>;

/// Check if the local MKVS cache contains the given key.
///
/// While get can be used to check if the MKVS as a whole contains
/// a given key, this function specifically guarantees that no remote
/// syncing will be invoked, only checking the local cache.
fn cache_contains_key(&self, ctx: Context, key: &[u8]) -> bool;

/// Update entry with given key.
///
/// If the database did not have this key present, [`None`] is returned.
Expand Down
2 changes: 1 addition & 1 deletion runtime/src/storage/mkvs/tree/insert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ impl Tree {
let node_ref = self.cache.borrow_mut().deref_node_ptr(
ctx,
ptr.clone(),
FetcherSyncGet::new(key, false),
Some(FetcherSyncGet::new(key, false)),
)?;

let (_, key_remainder) = key.split(bit_depth, key.bit_length());
Expand Down
2 changes: 1 addition & 1 deletion runtime/src/storage/mkvs/tree/iterator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ impl<'tree> TreeIterator<'tree> {
let node_ref = self.tree.cache.borrow_mut().deref_node_ptr(
&self.ctx,
ptr.clone(),
FetcherSyncIterate::new(&key, self.prefetch),
Some(FetcherSyncIterate::new(&key, self.prefetch)),
)?;

match classify_noderef!(?node_ref) {
Expand Down
32 changes: 27 additions & 5 deletions runtime/src/storage/mkvs/tree/lookup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,19 @@ impl<'a> ReadSyncFetcher for FetcherSyncGet<'a> {
impl Tree {
/// Get an existing key.
pub fn get(&self, ctx: Context, key: &[u8]) -> Fallible<Option<Vec<u8>>> {
self._get_top(ctx, key, false)
}

/// Check if the key exists in the local cache.
pub fn cache_contains_key(&self, ctx: Context, key: &[u8]) -> bool {
match self._get_top(ctx, key, true) {
Ok(Some(_)) => true,
Ok(None) => false,
Err(_) => false,
}
}

fn _get_top(&self, ctx: Context, key: &[u8], check_only: bool) -> Fallible<Option<Vec<u8>>> {
let ctx = ctx.freeze();
let boxed_key = key.to_vec();
let pending_root = self.cache.borrow().get_pending_root();
Expand All @@ -57,7 +70,7 @@ impl Tree {
// Remember where the path from root to target node ends (will end).
self.cache.borrow_mut().mark_position();

Ok(self._get(&ctx, pending_root, 0, &boxed_key, 0)?)
Ok(self._get(&ctx, pending_root, 0, &boxed_key, 0, check_only)?)
}

fn _get(
Expand All @@ -67,11 +80,17 @@ impl Tree {
bit_depth: Depth,
key: &Key,
depth: Depth,
check_only: bool,
) -> Fallible<Option<Value>> {
let node_ref =
self.cache
.borrow_mut()
.deref_node_ptr(ctx, ptr, FetcherSyncGet::new(key, false))?;
let node_ref = self.cache.borrow_mut().deref_node_ptr(
ctx,
ptr,
if check_only {
None
} else {
Some(FetcherSyncGet::new(key, false))
},
)?;

match classify_noderef!(?node_ref) {
NodeKind::None => {
Expand All @@ -90,6 +109,7 @@ impl Tree {
bit_depth + n.label_bit_length,
key,
depth,
check_only,
);
}

Expand All @@ -106,6 +126,7 @@ impl Tree {
bit_depth + n.label_bit_length,
key,
depth + 1,
check_only,
);
} else {
return self._get(
Expand All @@ -114,6 +135,7 @@ impl Tree {
bit_depth + n.label_bit_length,
key,
depth + 1,
check_only,
);
}
}
Expand Down
5 changes: 5 additions & 0 deletions runtime/src/storage/mkvs/tree/mkvs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ impl MKVS for Tree {
self.get(ctx, key).unwrap()
}

fn cache_contains_key(&self, ctx: Context, key: &[u8]) -> bool {
let _lock = self.lock.lock().unwrap();
self.cache_contains_key(ctx, key)
}

fn insert(&mut self, ctx: Context, key: &[u8], value: &[u8]) -> Option<Vec<u8>> {
let lock = self.lock.clone();
let _guard = lock.lock().unwrap();
Expand Down
6 changes: 3 additions & 3 deletions runtime/src/storage/mkvs/tree/remove.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ impl Tree {
let node_ref = self.cache.borrow_mut().deref_node_ptr(
ctx,
ptr.clone(),
FetcherSyncGet::new(key, true),
Some(FetcherSyncGet::new(key, true)),
)?;

match classify_noderef!(?node_ref) {
Expand Down Expand Up @@ -106,12 +106,12 @@ impl Tree {
remaining_left = self.cache.borrow_mut().deref_node_ptr(
ctx,
n.left.clone(),
FetcherSyncGet::new(key, true),
Some(FetcherSyncGet::new(key, true)),
)?;
remaining_right = self.cache.borrow_mut().deref_node_ptr(
ctx,
n.right.clone(),
FetcherSyncGet::new(key, true),
Some(FetcherSyncGet::new(key, true)),
)?;
} else {
unreachable!("node kind is Internal");
Expand Down
Loading

0 comments on commit fb20be9

Please sign in to comment.