mirror of
https://github.com/Start9Labs/patch-db.git
synced 2026-03-26 10:21:53 +00:00
builds again, tests underway
This commit is contained in:
committed by
Aiden McClelland
parent
09697a3c5a
commit
ebc666302b
@@ -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
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -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! {
|
||||
|
||||
Reference in New Issue
Block a user