use crate::determinism::CanonicalEventKey;
use crate::sched::{PendingActivation, ProcessId, SchedTime};
use crate::state::StateCellId;
pub fn canonical_key_of(a: &PendingActivation) -> (SchedTime, u32, u32, ProcessId) {
(
a.logical_order.0,
a.logical_order.1 as u32,
a.reconv_iter,
a.proc,
)
}
pub fn sort_ready_set(ready: &mut [PendingActivation]) {
ready.sort_by_key(|a| {
(
a.logical_order.0,
a.logical_order.1 as u32,
a.reconv_iter,
a.logical_order.2,
)
});
}
pub struct WriteBuffer<T> {
entries: Vec<(CanonicalEventKey, StateCellId, T)>,
}
impl<T> Default for WriteBuffer<T> {
fn default() -> Self {
Self {
entries: Vec::new(),
}
}
}
impl<T> WriteBuffer<T> {
pub fn new() -> Self {
Self::default()
}
pub fn push(&mut self, key: CanonicalEventKey, cell: StateCellId, value: T) {
self.entries.push((key, cell, value));
}
pub fn resolve_last_write_wins(self) -> Vec<(StateCellId, T)> {
let mut by_cell: std::collections::BTreeMap<StateCellId, (CanonicalEventKey, T)> =
std::collections::BTreeMap::new();
for (key, cell, value) in self.entries {
match by_cell.get(&cell) {
Some((existing_key, _)) if *existing_key >= key => {
}
_ => {
by_cell.insert(cell, (key, value));
}
}
}
by_cell
.into_iter()
.map(|(cell, (_, value))| (cell, value))
.collect()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::sched::ResumeArg;
use vj_abi::Region;
fn activation(
id: u64,
proc: ProcessId,
ticks: u64,
region: Region,
reconv_iter: u32,
registration_order: u64,
) -> PendingActivation {
PendingActivation {
id,
proc,
arg: ResumeArg::Start,
reconv_iter,
logical_order: (SchedTime { ticks }, region, registration_order),
}
}
fn key(
ticks: u64,
region: Region,
reconv_iter: u32,
proc: ProcessId,
seq: u64,
) -> CanonicalEventKey {
CanonicalEventKey {
vtime: SchedTime { ticks },
region_ordinal: region as u32,
reconv_iter,
canonical_process_id: proc,
local_send_seq: seq,
}
}
#[test]
fn sort_ready_set_is_insertion_order_independent() {
let a = activation(1, 10, 5, Region::Active, 0, 0);
let b = activation(2, 11, 5, Region::Active, 0, 1);
let c = activation(3, 12, 5, Region::Active, 0, 2);
let d = activation(4, 13, 5, Region::Active, 0, 3);
let mut order1 = vec![c, a, d, b];
let mut order2 = vec![b, d, a, c];
sort_ready_set(&mut order1);
sort_ready_set(&mut order2);
let procs1: Vec<ProcessId> = order1.iter().map(|x| x.proc).collect();
let procs2: Vec<ProcessId> = order2.iter().map(|x| x.proc).collect();
assert_eq!(procs1, procs2);
assert_eq!(procs1, vec![10, 11, 12, 13]);
}
#[test]
fn sort_ready_set_orders_by_time_then_region_then_reconv_iter_then_registration() {
let earliest_time = activation(1, 100, 1, Region::Active, 0, 5); let later_time_early_region = activation(2, 101, 2, Region::Active, 0, 9);
let later_time_later_region = activation(3, 102, 2, Region::Nba, 0, 0);
let same_tr_early_reconv = activation(4, 103, 2, Region::Nba, 1, 9);
let same_tr_late_reconv_early_reg = activation(5, 104, 2, Region::Nba, 2, 0);
let same_tr_late_reconv_late_reg = activation(6, 105, 2, Region::Nba, 2, 1);
let mut ready = vec![
same_tr_late_reconv_late_reg,
same_tr_early_reconv,
later_time_later_region,
earliest_time,
same_tr_late_reconv_early_reg,
later_time_early_region,
];
sort_ready_set(&mut ready);
let procs: Vec<ProcessId> = ready.iter().map(|x| x.proc).collect();
assert_eq!(procs, vec![100, 101, 102, 103, 104, 105]);
}
#[test]
fn write_buffer_last_write_wins_is_key_order_not_push_order() {
let cell = StateCellId(7);
let k0 = key(1, Region::Active, 0, 0, 0);
let k1 = key(2, Region::Active, 0, 0, 0);
let k2 = key(3, Region::Active, 0, 0, 0);
assert!(k0 < k1);
assert!(k1 < k2);
let mut buf: WriteBuffer<u32> = WriteBuffer::new();
buf.push(k2, cell, 200);
buf.push(k0, cell, 0);
buf.push(k1, cell, 100);
let resolved = buf.resolve_last_write_wins();
assert_eq!(resolved, vec![(cell, 200)]);
}
#[test]
fn write_buffer_out_of_order_submission_still_commits_in_key_order() {
let cell = StateCellId(3);
let k_t5 = key(5, Region::Nba, 0, 0, 0);
let k_t3 = key(3, Region::Nba, 0, 0, 0);
let mut buf: WriteBuffer<&'static str> = WriteBuffer::new();
buf.push(k_t5, cell, "t5-value");
buf.push(k_t3, cell, "t3-value");
let resolved = buf.resolve_last_write_wins();
assert_eq!(resolved, vec![(cell, "t5-value")]);
}
#[test]
fn dt010_single_canonical_key_type_used_by_both_ready_set_and_write_buffer() {
let a = activation(1, 42, 5, Region::Active, 0, 0);
let (ticks, region_ordinal, reconv_iter, proc) = canonical_key_of(&a);
let built_key = CanonicalEventKey {
vtime: ticks,
region_ordinal,
reconv_iter,
canonical_process_id: proc,
local_send_seq: 0,
};
let mut buf: WriteBuffer<u8> = WriteBuffer::new();
buf.push(built_key, StateCellId(1), 1);
let resolved = buf.resolve_last_write_wins();
assert_eq!(resolved, vec![(StateCellId(1), 1)]);
}
}