vole_document/store/
io.rs1use std::cell::Cell;
20use std::rc::Rc;
21
22#[derive(Debug, Clone, Default)]
27pub struct IoCounters {
28 inner: Rc<IoInner>,
29}
30
31#[derive(Debug, Default)]
32struct IoInner {
33 descriptor_bytes: Cell<u64>,
34 manifest_bytes: Cell<u64>,
35 index_bytes: Cell<u64>,
36 seed_bytes: Cell<u64>,
37 descriptor_reads: Cell<u64>,
38}
39
40impl IoCounters {
41 pub fn new() -> Self {
43 IoCounters {
44 inner: Rc::new(IoInner::default()),
45 }
46 }
47
48 pub fn handle(&self) -> Self {
50 IoCounters {
51 inner: Rc::clone(&self.inner),
52 }
53 }
54
55 pub fn add_descriptor(&self, bytes: u64) {
57 self.inner
58 .descriptor_bytes
59 .set(self.inner.descriptor_bytes.get().saturating_add(bytes));
60 self.inner
61 .descriptor_reads
62 .set(self.inner.descriptor_reads.get().saturating_add(1));
63 }
64
65 pub fn add_manifest(&self, bytes: u64) {
67 self.inner
68 .manifest_bytes
69 .set(self.inner.manifest_bytes.get().saturating_add(bytes));
70 }
71
72 pub fn add_index(&self, bytes: u64) {
74 self.inner
75 .index_bytes
76 .set(self.inner.index_bytes.get().saturating_add(bytes));
77 }
78
79 pub fn add_seed(&self, bytes: u64) {
81 self.inner
82 .seed_bytes
83 .set(self.inner.seed_bytes.get().saturating_add(bytes));
84 }
85
86 pub fn descriptor_reads(&self) -> u64 {
88 self.inner.descriptor_reads.get()
89 }
90
91 pub fn snapshot(&self) -> IoSnapshot {
93 IoSnapshot {
94 descriptor_bytes: self.inner.descriptor_bytes.get(),
95 manifest_bytes: self.inner.manifest_bytes.get(),
96 index_bytes: self.inner.index_bytes.get(),
97 seed_bytes: self.inner.seed_bytes.get(),
98 }
99 }
100}
101
102#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
105pub struct IoSnapshot {
106 pub descriptor_bytes: u64,
108 pub manifest_bytes: u64,
110 pub index_bytes: u64,
112 pub seed_bytes: u64,
114}
115
116impl IoSnapshot {
117 pub fn delta(&self, later: &IoSnapshot) -> IoSnapshot {
120 IoSnapshot {
121 descriptor_bytes: later.descriptor_bytes.saturating_sub(self.descriptor_bytes),
122 manifest_bytes: later.manifest_bytes.saturating_sub(self.manifest_bytes),
123 index_bytes: later.index_bytes.saturating_sub(self.index_bytes),
124 seed_bytes: later.seed_bytes.saturating_sub(self.seed_bytes),
125 }
126 }
127
128 pub fn total(&self) -> u64 {
130 self.descriptor_bytes
131 .saturating_add(self.manifest_bytes)
132 .saturating_add(self.index_bytes)
133 .saturating_add(self.seed_bytes)
134 }
135
136 pub fn plus(&self, other: &IoSnapshot) -> IoSnapshot {
138 IoSnapshot {
139 descriptor_bytes: self.descriptor_bytes.saturating_add(other.descriptor_bytes),
140 manifest_bytes: self.manifest_bytes.saturating_add(other.manifest_bytes),
141 index_bytes: self.index_bytes.saturating_add(other.index_bytes),
142 seed_bytes: self.seed_bytes.saturating_add(other.seed_bytes),
143 }
144 }
145}
146
147#[cfg(test)]
148mod tests {
149 use super::*;
150
151 #[test]
152 fn handles_share_and_delta_sums_correctly() {
153 let a = IoCounters::new();
154 let b = a.handle();
155 a.add_descriptor(100);
156 b.add_manifest(10);
157 b.add_index(7);
158 b.add_seed(3);
159 let s = a.snapshot();
160 assert_eq!(s.descriptor_bytes, 100);
161 assert_eq!(s.manifest_bytes, 10);
162 assert_eq!(s.index_bytes, 7);
163 assert_eq!(s.seed_bytes, 3);
164 assert_eq!(s.total(), 120);
165 assert_eq!(a.descriptor_reads(), 1);
166 assert_eq!(b.descriptor_reads(), 1);
167 }
168
169 #[test]
170 fn independent_counters_do_not_leak() {
171 let a = IoCounters::new();
172 let b = IoCounters::new();
173 a.add_seed(5);
174 assert_eq!(b.snapshot().total(), 0);
175 }
176
177 #[test]
178 fn delta_is_non_negative_and_additive() {
179 let c = IoCounters::new();
180 let before = c.snapshot();
181 c.add_descriptor(4);
182 c.add_seed(9);
183 let after = c.snapshot();
184 let d = before.delta(&after);
185 assert_eq!(d.descriptor_bytes, 4);
186 assert_eq!(d.seed_bytes, 9);
187 assert_eq!(d.total(), 13);
188 assert_eq!(after.delta(&before).total(), 0);
190 assert_eq!(d.plus(&d).total(), 26);
191 }
192}