1use crate::determinism::CanonicalEventKey;
14use crate::sched::{PendingActivation, ProcessId, SchedTime};
15use crate::state::StateCellId;
16
17pub fn canonical_key_of(a: &PendingActivation) -> (SchedTime, u32, u32, ProcessId) {
22 (
23 a.logical_order.0,
24 a.logical_order.1 as u32,
25 a.reconv_iter,
26 a.proc,
27 )
28}
29
30pub fn sort_ready_set(ready: &mut [PendingActivation]) {
36 ready.sort_by_key(|a| {
37 (
38 a.logical_order.0,
39 a.logical_order.1 as u32,
40 a.reconv_iter,
41 a.logical_order.2,
42 )
43 });
44}
45
46pub struct WriteBuffer<T> {
58 entries: Vec<(CanonicalEventKey, StateCellId, T)>,
59}
60
61impl<T> Default for WriteBuffer<T> {
62 fn default() -> Self {
63 Self {
64 entries: Vec::new(),
65 }
66 }
67}
68
69impl<T> WriteBuffer<T> {
70 pub fn new() -> Self {
71 Self::default()
72 }
73
74 pub fn push(&mut self, key: CanonicalEventKey, cell: StateCellId, value: T) {
75 self.entries.push((key, cell, value));
76 }
77
78 pub fn resolve_last_write_wins(self) -> Vec<(StateCellId, T)> {
83 let mut by_cell: std::collections::BTreeMap<StateCellId, (CanonicalEventKey, T)> =
84 std::collections::BTreeMap::new();
85 for (key, cell, value) in self.entries {
86 match by_cell.get(&cell) {
87 Some((existing_key, _)) if *existing_key >= key => {
88 }
91 _ => {
92 by_cell.insert(cell, (key, value));
93 }
94 }
95 }
96 by_cell
97 .into_iter()
98 .map(|(cell, (_, value))| (cell, value))
99 .collect()
100 }
101}
102
103#[cfg(test)]
104mod tests {
105 use super::*;
106 use crate::sched::ResumeArg;
107 use vj_abi::Region;
108
109 fn activation(
110 id: u64,
111 proc: ProcessId,
112 ticks: u64,
113 region: Region,
114 reconv_iter: u32,
115 registration_order: u64,
116 ) -> PendingActivation {
117 PendingActivation {
118 id,
119 proc,
120 arg: ResumeArg::Start,
121 reconv_iter,
122 logical_order: (SchedTime { ticks }, region, registration_order),
123 }
124 }
125
126 fn key(
127 ticks: u64,
128 region: Region,
129 reconv_iter: u32,
130 proc: ProcessId,
131 seq: u64,
132 ) -> CanonicalEventKey {
133 CanonicalEventKey {
134 vtime: SchedTime { ticks },
135 region_ordinal: region as u32,
136 reconv_iter,
137 canonical_process_id: proc,
138 local_send_seq: seq,
139 }
140 }
141
142 #[test]
143 fn sort_ready_set_is_insertion_order_independent() {
144 let a = activation(1, 10, 5, Region::Active, 0, 0);
145 let b = activation(2, 11, 5, Region::Active, 0, 1);
146 let c = activation(3, 12, 5, Region::Active, 0, 2);
147 let d = activation(4, 13, 5, Region::Active, 0, 3);
148
149 let mut order1 = vec![c, a, d, b];
150 let mut order2 = vec![b, d, a, c];
151
152 sort_ready_set(&mut order1);
153 sort_ready_set(&mut order2);
154
155 let procs1: Vec<ProcessId> = order1.iter().map(|x| x.proc).collect();
156 let procs2: Vec<ProcessId> = order2.iter().map(|x| x.proc).collect();
157 assert_eq!(procs1, procs2);
158 assert_eq!(procs1, vec![10, 11, 12, 13]);
159 }
160
161 #[test]
162 fn sort_ready_set_orders_by_time_then_region_then_reconv_iter_then_registration() {
163 let earliest_time = activation(1, 100, 1, Region::Active, 0, 5); let later_time_early_region = activation(2, 101, 2, Region::Active, 0, 9);
168 let later_time_later_region = activation(3, 102, 2, Region::Nba, 0, 0);
169 let same_tr_early_reconv = activation(4, 103, 2, Region::Nba, 1, 9);
170 let same_tr_late_reconv_early_reg = activation(5, 104, 2, Region::Nba, 2, 0);
171 let same_tr_late_reconv_late_reg = activation(6, 105, 2, Region::Nba, 2, 1);
172
173 let mut ready = vec![
174 same_tr_late_reconv_late_reg,
175 same_tr_early_reconv,
176 later_time_later_region,
177 earliest_time,
178 same_tr_late_reconv_early_reg,
179 later_time_early_region,
180 ];
181
182 sort_ready_set(&mut ready);
183
184 let procs: Vec<ProcessId> = ready.iter().map(|x| x.proc).collect();
185 assert_eq!(procs, vec![100, 101, 102, 103, 104, 105]);
186 }
187
188 #[test]
189 fn write_buffer_last_write_wins_is_key_order_not_push_order() {
190 let cell = StateCellId(7);
191 let k0 = key(1, Region::Active, 0, 0, 0);
192 let k1 = key(2, Region::Active, 0, 0, 0);
193 let k2 = key(3, Region::Active, 0, 0, 0);
194 assert!(k0 < k1);
195 assert!(k1 < k2);
196
197 let mut buf: WriteBuffer<u32> = WriteBuffer::new();
198 buf.push(k2, cell, 200);
200 buf.push(k0, cell, 0);
201 buf.push(k1, cell, 100);
202
203 let resolved = buf.resolve_last_write_wins();
204 assert_eq!(resolved, vec![(cell, 200)]);
205 }
206
207 #[test]
208 fn write_buffer_out_of_order_submission_still_commits_in_key_order() {
209 let cell = StateCellId(3);
210 let k_t5 = key(5, Region::Nba, 0, 0, 0);
211 let k_t3 = key(3, Region::Nba, 0, 0, 0);
212
213 let mut buf: WriteBuffer<&'static str> = WriteBuffer::new();
214 buf.push(k_t5, cell, "t5-value");
216 buf.push(k_t3, cell, "t3-value");
217
218 let resolved = buf.resolve_last_write_wins();
219 assert_eq!(resolved, vec![(cell, "t5-value")]);
220 }
221
222 #[test]
223 fn dt010_single_canonical_key_type_used_by_both_ready_set_and_write_buffer() {
224 let a = activation(1, 42, 5, Region::Active, 0, 0);
225 let (ticks, region_ordinal, reconv_iter, proc) = canonical_key_of(&a);
226 let built_key = CanonicalEventKey {
227 vtime: ticks,
228 region_ordinal,
229 reconv_iter,
230 canonical_process_id: proc,
231 local_send_seq: 0,
232 };
233
234 let mut buf: WriteBuffer<u8> = WriteBuffer::new();
235 buf.push(built_key, StateCellId(1), 1);
236 let resolved = buf.resolve_last_write_wins();
237 assert_eq!(resolved, vec![(StateCellId(1), 1)]);
238 }
239}