builds again, tests underway

This commit is contained in:
Keagan McClelland
2022-01-03 18:33:21 -07:00
committed by Aiden McClelland
parent 09697a3c5a
commit ebc666302b
3 changed files with 111 additions and 68 deletions

View File

@@ -7,7 +7,7 @@ use crate::{
LockSet, LockSet,
}, },
}; };
use imbl::{ordset, OrdMap, OrdSet}; use imbl::{ordmap, ordset, OrdMap, OrdSet};
use tokio::sync::oneshot; use tokio::sync::oneshot;
use tracing::{debug, error, info, warn}; use tracing::{debug, error, info, warn};
@@ -217,15 +217,14 @@ fn kill_deadlocked(request_queue: &mut VecDeque<(Request, OrdSet<HandleId>)>, tr
} }
} }
fn deadlock_scan<'a>(queue: &'a VecDeque<(Request, OrdSet<HandleId>)>) -> Vec<&'a Request> { pub(super) fn deadlock_scan<'a>(
queue: &'a VecDeque<(Request, OrdSet<HandleId>)>,
) -> Vec<&'a Request> {
let (wait_map, mut req_map) = queue let (wait_map, mut req_map) = queue
.iter() .iter()
.map(|(req, set)| ((&req.lock_info.handle_id, set, req))) .map(|(req, set)| ((&req.lock_info.handle_id, set, req)))
.fold( .fold(
( (ordmap! {}, ordmap! {}),
OrdMap::<&'a HandleId, &'a OrdSet<HandleId>>::new(),
OrdMap::<&'a HandleId, &'a Request>::new(),
),
|(mut wmap, mut rmap), (id, wset, req)| { |(mut wmap, mut rmap), (id, wset, req)| {
( (
{ {
@@ -239,25 +238,6 @@ fn deadlock_scan<'a>(queue: &'a VecDeque<(Request, OrdSet<HandleId>)>) -> Vec<&'
) )
}, },
); );
fn path_to<'a>(
graph: &OrdMap<&'a HandleId, &'a OrdSet<HandleId>>,
root: &'a HandleId,
node: &'a HandleId,
) -> OrdSet<&'a HandleId> {
if node == root {
return ordset![root];
}
match graph.get(node) {
None => ordset![],
Some(s) => s
.iter()
.find_map(|h| Some(path_to(graph, root, h)).filter(|s| s.is_empty()))
.map_or(ordset![], |mut s| {
s.insert(node);
s
}),
}
}
for (root, wait_set) in wait_map.iter() { for (root, wait_set) in wait_map.iter() {
let cycle = wait_set let cycle = wait_set
.iter() .iter()
@@ -276,3 +256,23 @@ fn deadlock_scan<'a>(queue: &'a VecDeque<(Request, OrdSet<HandleId>)>) -> Vec<&'
} }
vec![] vec![]
} }
pub(super) fn path_to<'a>(
graph: &OrdMap<&'a HandleId, &'a OrdSet<HandleId>>,
root: &'a HandleId,
node: &'a HandleId,
) -> OrdSet<&'a HandleId> {
if node == root {
return ordset![root];
}
match graph.get(node) {
None => ordset![],
Some(s) => s
.iter()
.find_map(|h| Some(path_to(graph, root, h)).filter(|s| s.is_empty()))
.map_or(ordset![], |mut s| {
s.insert(node);
s
}),
}
}

View File

@@ -3,6 +3,8 @@ mod bookkeeper;
mod log_utils; mod log_utils;
mod natural; mod natural;
mod order_enforcer; mod order_enforcer;
#[cfg(test)]
pub(crate) mod proptest;
mod trie; mod trie;
use imbl::{ordmap, ordset, OrdMap, OrdSet}; use imbl::{ordmap, ordset, OrdMap, OrdSet};
@@ -66,23 +68,6 @@ impl Locker {
ptr: JsonPointer, ptr: JsonPointer,
lock_type: LockType, lock_type: LockType,
) -> Result<Guard, LockError> { ) -> Result<Guard, LockError> {
// Local Definitions
struct CancelGuard {
lock_info: Option<LockInfo>,
channel: Option<oneshot::Sender<LockInfo>>,
recv: oneshot::Receiver<Result<Guard, LockError>>,
}
impl Drop for CancelGuard {
fn drop(&mut self) {
if let (Some(lock_info), Some(channel)) =
(self.lock_info.take(), self.channel.take())
{
self.recv.close();
let _ = channel.send(lock_info);
}
}
}
// Pertinent Logic // Pertinent Logic
let lock_info = LockInfo { let lock_info = LockInfo {
handle_id, handle_id,
@@ -107,6 +92,20 @@ impl Locker {
cancel_guard.channel.take(); cancel_guard.channel.take();
res res
} }
} // Local Definitions
#[derive(Debug)]
struct CancelGuard {
lock_info: Option<LockInfo>,
channel: Option<oneshot::Sender<LockInfo>>,
recv: oneshot::Receiver<Result<Guard, LockError>>,
}
impl Drop for CancelGuard {
fn drop(&mut self) {
if let (Some(lock_info), Some(channel)) = (self.lock_info.take(), self.channel.take()) {
self.recv.close();
let _ = channel.send(lock_info);
}
}
} }
#[derive(Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord)] #[derive(Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord)]

View File

@@ -1,30 +1,31 @@
#[cfg(test)] #[cfg(test)]
mod proptest { mod tests {
use std::collections::HashMap; use std::collections::HashMap;
use json_ptr::JsonPointer; use json_ptr::JsonPointer;
use tokio::sync::oneshot;
use crate::handle::HandleId; use crate::handle::HandleId;
use crate::locker::{Guard, LockType}; use crate::locker::{CancelGuard, Guard, LockInfo, LockType, Request};
use proptest::prelude::*; use proptest::prelude::*;
enum Action { // enum Action {
Acquire { // Acquire {
lock_type: LockType, // lock_type: LockType,
ptr: JsonPointer, // ptr: JsonPointer,
}, // },
Release(JsonPointer), // Release(JsonPointer),
} // }
struct Session { // struct Session {
// session id // // session id
id: HandleId, // id: HandleId,
// list of actions and whether or not they have been completed (await returns before test freezes state) // // list of actions and whether or not they have been completed (await returns before test freezes state)
actions: Vec<(Action, bool)>, // actions: Vec<(Action, bool)>,
// lookup table for (json pointers, action indices) -> release action // // lookup table for (json pointers, action indices) -> release action
guard: HashMap<(JsonPointer, usize), Guard>, // guard: HashMap<(JsonPointer, usize), Guard>,
} // }
type Traversal = Vec<usize>; // type Traversal = Vec<usize>;
// randomly select the type of lock we are requesting // randomly select the type of lock we are requesting
fn arb_lock_type() -> BoxedStrategy<LockType> { fn arb_lock_type() -> BoxedStrategy<LockType> {
@@ -36,20 +37,63 @@ mod proptest {
.boxed() .boxed()
} }
// randomly generate session ids
prop_compose! { prop_compose! {
fn arb_handle_id()(i in any::<u64>()) -> HandleId { fn arb_handle_id(n: u64)(x in 0..n) -> HandleId {
HandleId { HandleId {
id: i, id: x,
#[cfg(feature = "trace")]
trace: None,
} }
} }
} }
// the test trie we will be using is an arbitrarily deep binary tree of L and R paths. This will be sufficient to fn arb_json_ptr(max_size: usize) -> BoxedStrategy<JsonPointer> {
// test sibling concurrency and won't introduce any unnecessary complexity to the suite. This is the primitive fork (1..max_size)
// choice generator .prop_flat_map(|n| {
fn arb_json_fork_choice() -> BoxedStrategy<char> { let s = proptest::bool::ANY.prop_map(|b| if b { "b" } else { "a" });
prop_oneof![Just('L'), Just('R'),].boxed() proptest::collection::vec_deque(s, n).prop_flat_map(|v| {
let mut ptr = JsonPointer::default();
for seg in v {
ptr.push_end(seg);
}
Just(ptr)
})
})
.boxed()
}
fn arb_lock_info(session_bound: u64, ptr_max_size: usize) -> BoxedStrategy<LockInfo> {
arb_handle_id(session_bound)
.prop_flat_map(move |handle_id| {
arb_json_ptr(ptr_max_size).prop_flat_map(move |ptr| {
let handle_id = handle_id.clone();
arb_lock_type().prop_map(move |ty| LockInfo {
handle_id: handle_id.clone(),
ty,
ptr: ptr.clone(),
})
})
})
.boxed()
}
prop_compose! {
fn arb_request(session_bound: u64, ptr_max_size: usize)(li in arb_lock_info(session_bound, ptr_max_size)) -> (Request, CancelGuard) {
let (cancel_send, cancel_recv) = oneshot::channel();
let (guard_send, guard_recv) = oneshot::channel();
let r = Request {
lock_info: li.clone(),
cancel: Some(cancel_recv),
completion: guard_send,
};
let c = CancelGuard {
lock_info: Some(li),
channel: Some(cancel_send),
recv: guard_recv,
};
(r, c)
}
} }
proptest! { proptest! {