rustdb/wmap.rs
1use crate::{BTreeMap, Data, Storage};
2use std::cmp::min;
3
4#[derive(Default)]
5/// Slice of Data to be written to storage.
6pub struct DataSlice {
7 /// Slice data.
8 pub data: Data,
9 /// Start of slice.
10 pub off: usize,
11 /// Length of slice.
12 pub len: usize,
13}
14
15impl DataSlice {
16 /// Get reference to the whole slice.
17 pub fn all(&self) -> &[u8] {
18 &self.data[self.off..self.off + self.len]
19 }
20 /// Get reference to part of slice.
21 pub fn part(&self, off: usize, len: usize) -> &[u8] {
22 &self.data[self.off + off..self.off + off + len]
23 }
24 /// Trim specified amount from start of slice.
25 pub fn trim(&mut self, trim: usize) {
26 self.off += trim;
27 self.len -= trim;
28 }
29 /// Take the data.
30 pub fn take(&mut self) -> Data {
31 std::mem::take(&mut self.data)
32 }
33}
34
35#[derive(Default)]
36/// Updateable storage based on some underlying storage.
37pub struct WMap {
38 /// Map of writes. Key is the end of the slice.
39 map: BTreeMap<u64, DataSlice>,
40}
41
42impl WMap {
43 /// Is the map empty?
44 pub fn is_empty(&self) -> bool {
45 self.map.is_empty()
46 }
47
48 /// Number of key-value pairs in the map.
49 pub fn len(&self) -> usize {
50 self.map.len()
51 }
52
53 /// Take the map and convert it to a Vec.
54 pub fn to_vec(&mut self) -> Vec<(u64, DataSlice)> {
55 let map = std::mem::take(&mut self.map);
56 let mut result = Vec::with_capacity(map.len());
57 for (end, v) in map {
58 let start = end - v.len as u64;
59 result.push((start, v));
60 }
61 result
62 }
63
64 /// Write the map into storage.
65 pub fn to_storage(&self, stg: &mut dyn Storage) {
66 for (end, v) in self.map.iter() {
67 let start = end - v.len as u64;
68 stg.write_data(start, v.data.clone(), v.off, v.len);
69 }
70 }
71
72 #[cfg(not(feature = "pstd"))]
73 /// Write to storage, existing writes which overlap with new write need to be trimmed or removed.
74 pub fn write(&mut self, start: u64, data: Data, off: usize, len: usize) {
75 if len != 0 {
76 let (mut insert, mut remove) = (Vec::new(), Vec::new());
77 let end = start + len as u64;
78 for (ee, v) in self.map.range_mut(start + 1..) {
79 let ee = *ee;
80 let es = ee - v.len as u64; // Existing write Start.
81 if es >= end {
82 // Existing write starts after end of new write, nothing to do.
83 break;
84 } else if start <= es {
85 if end < ee {
86 // New write starts before existing write, but doesn't subsume it. Trim existing write.
87 v.trim((end - es) as usize);
88 break;
89 }
90 // New write subsumes existing write entirely, remove existing write.
91 remove.push(ee);
92 } else if end < ee {
93 // New write starts in middle of existing write, ends before end of existing write,
94 // put start of existing write in insert list, trim existing write.
95 insert.push((es, v.data.clone(), v.off, (start - es) as usize));
96 v.trim((end - es) as usize);
97 break;
98 } else {
99 // New write starts in middle of existing write, ends after existing write,
100 // put start of existing write in insert list, remove existing write.
101 insert.push((es, v.take(), v.off, (start - es) as usize));
102 remove.push(ee);
103 }
104 }
105 for end in remove {
106 self.map.remove(&end);
107 }
108 for (start, data, off, len) in insert {
109 self.map
110 .insert(start + len as u64, DataSlice { data, off, len });
111 }
112 self.map
113 .insert(start + len as u64, DataSlice { data, off, len });
114 }
115 }
116
117 #[cfg(feature = "pstd")]
118 /// Write to storage, existing writes which overlap with new write need to be trimmed or removed.
119 pub fn write(&mut self, start: u64, data: Data, off: usize, len: usize) {
120 if len != 0 {
121 let end = start + len as u64;
122 let mut c = self
123 .map
124 .lower_bound_mut(std::ops::Bound::Excluded(&start))
125 .with_mutable_key();
126 while let Some((eend, v)) = c.next() {
127 let ee = *eend;
128 let es = ee - v.len as u64; // Existing write Start.
129 if es >= end {
130 // Existing write starts after end of new write, nothing to do.
131 c.prev();
132 break;
133 } else if start <= es {
134 if end < ee {
135 // New write starts before existing write, but doesn't subsume it. Trim existing write.
136 v.trim((end - es) as usize);
137 c.prev();
138 break;
139 }
140 // New write subsumes existing write entirely, remove existing write.
141 c.remove_prev();
142 } else if end < ee {
143 // New write starts in middle of existing write, ends before end of existing write,
144 // trim existing write, insert start of existing write.
145 let (data, off, len) = (v.data.clone(), v.off, (start - es) as usize);
146 v.trim((end - es) as usize);
147 c.prev();
148 c.insert_before_unchecked(es + len as u64, DataSlice { data, off, len });
149 break;
150 } else {
151 // New write starts in middle of existing write, ends after existing write,
152 // Trim existing write ( modifies key, but this is ok as ordering is not affected ).
153 v.len = (start - es) as usize;
154 *eend = es + v.len as u64;
155 }
156 }
157 // Insert the new write.
158 c.insert_after_unchecked(start + len as u64, DataSlice { data, off, len });
159 }
160 }
161
162 /// Read from storage, taking map of existing writes into account. Unwritten ranges are read from underlying storage.
163 pub fn read(&self, start: u64, data: &mut [u8], u: &dyn Storage) {
164 let len = data.len();
165 if len != 0 {
166 let mut done = 0;
167 for (&end, v) in self.map.range(start + 1..) {
168 let es = end - v.len as u64; // Existing write Start.
169 let doff = start + done as u64;
170 if es > doff {
171 // Read from underlying storage.
172 let a = min(len - done, (es - doff) as usize);
173 u.read(doff, &mut data[done..done + a]);
174 done += a;
175 if done == len {
176 return;
177 }
178 }
179 // Use existing write.
180 let skip = (start + done as u64 - es) as usize;
181 let a = min(len - done, v.len - skip);
182 data[done..done + a].copy_from_slice(v.part(skip, a));
183 done += a;
184 if done == len {
185 return;
186 }
187 }
188 u.read(start + done as u64, &mut data[done..]);
189 }
190 }
191}