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,
},
};
use imbl::{ordset, OrdMap, OrdSet};
use imbl::{ordmap, ordset, OrdMap, OrdSet};
use tokio::sync::oneshot;
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
.iter()
.map(|(req, set)| ((&req.lock_info.handle_id, set, req)))
.fold(
(
OrdMap::<&'a HandleId, &'a OrdSet<HandleId>>::new(),
OrdMap::<&'a HandleId, &'a Request>::new(),
),
(ordmap! {}, ordmap! {}),
|(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() {
let cycle = wait_set
.iter()
@@ -276,3 +256,23 @@ fn deadlock_scan<'a>(queue: &'a VecDeque<(Request, OrdSet<HandleId>)>) -> 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 natural;
mod order_enforcer;
#[cfg(test)]
pub(crate) mod proptest;
mod trie;
use imbl::{ordmap, ordset, OrdMap, OrdSet};
@@ -66,23 +68,6 @@ impl Locker {
ptr: JsonPointer,
lock_type: LockType,
) -> 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
let lock_info = LockInfo {
handle_id,
@@ -107,6 +92,20 @@ impl Locker {
cancel_guard.channel.take();
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)]

View File

@@ -1,30 +1,31 @@
#[cfg(test)]
mod proptest {
mod tests {
use std::collections::HashMap;
use json_ptr::JsonPointer;
use tokio::sync::oneshot;
use crate::handle::HandleId;
use crate::locker::{Guard, LockType};
use crate::locker::{CancelGuard, Guard, LockInfo, LockType, Request};
use proptest::prelude::*;
enum Action {
Acquire {
lock_type: LockType,
ptr: JsonPointer,
},
Release(JsonPointer),
}
// enum Action {
// Acquire {
// lock_type: LockType,
// ptr: JsonPointer,
// },
// Release(JsonPointer),
// }
struct Session {
// session id
id: HandleId,
// list of actions and whether or not they have been completed (await returns before test freezes state)
actions: Vec<(Action, bool)>,
// lookup table for (json pointers, action indices) -> release action
guard: HashMap<(JsonPointer, usize), Guard>,
}
type Traversal = Vec<usize>;
// struct Session {
// // session id
// id: HandleId,
// // list of actions and whether or not they have been completed (await returns before test freezes state)
// actions: Vec<(Action, bool)>,
// // lookup table for (json pointers, action indices) -> release action
// guard: HashMap<(JsonPointer, usize), Guard>,
// }
// type Traversal = Vec<usize>;
// randomly select the type of lock we are requesting
fn arb_lock_type() -> BoxedStrategy<LockType> {
@@ -36,20 +37,63 @@ mod proptest {
.boxed()
}
// randomly generate session ids
prop_compose! {
fn arb_handle_id()(i in any::<u64>()) -> HandleId {
fn arb_handle_id(n: u64)(x in 0..n) -> 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
// test sibling concurrency and won't introduce any unnecessary complexity to the suite. This is the primitive fork
// choice generator
fn arb_json_fork_choice() -> BoxedStrategy<char> {
prop_oneof![Just('L'), Just('R'),].boxed()
fn arb_json_ptr(max_size: usize) -> BoxedStrategy<JsonPointer> {
(1..max_size)
.prop_flat_map(|n| {
let s = proptest::bool::ANY.prop_map(|b| if b { "b" } else { "a" });
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! {