/rust/registry/src/index.crates.io-1949cf8c6b5b557f/wasefire-store-0.2.4/src/fragment.rs
Line | Count | Source |
1 | | // Copyright 2021 Google LLC |
2 | | // |
3 | | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | | // you may not use this file except in compliance with the License. |
5 | | // You may obtain a copy of the License at |
6 | | // |
7 | | // http://www.apache.org/licenses/LICENSE-2.0 |
8 | | // |
9 | | // Unless required by applicable law or agreed to in writing, software |
10 | | // distributed under the License is distributed on an "AS IS" BASIS, |
11 | | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | | // See the License for the specific language governing permissions and |
13 | | // limitations under the License. |
14 | | |
15 | | //! Support for fragmented entries. |
16 | | //! |
17 | | //! This module permits to handle entries larger than the [maximum value |
18 | | //! length](Store::max_value_length) by storing ordered consecutive fragments in a sequence of keys. |
19 | | //! The first keys hold fragments of maximal length, followed by a possibly partial fragment. The |
20 | | //! remaining keys are not used. |
21 | | |
22 | | use alloc::vec::Vec; |
23 | | use core::ops::Range; |
24 | | |
25 | | use crate::{Storage, Store, StoreError, StoreHandle, StoreResult, StoreUpdate}; |
26 | | |
27 | | /// Represents a sequence of keys. |
28 | | #[allow(clippy::len_without_is_empty)] |
29 | | pub trait Keys { |
30 | | /// Returns the number of keys. |
31 | | fn len(&self) -> usize; |
32 | | |
33 | | /// Returns the position of a key in the sequence. |
34 | | fn pos(&self, key: usize) -> Option<usize>; |
35 | | |
36 | | /// Returns the key of a position in the sequence. |
37 | | /// |
38 | | /// # Preconditions |
39 | | /// |
40 | | /// The position must be within the length: `pos` < [`Self::len`]. |
41 | | fn key(&self, pos: usize) -> usize; |
42 | | } |
43 | | |
44 | | impl Keys for Range<usize> { |
45 | 0 | fn len(&self) -> usize { |
46 | 0 | self.end.saturating_sub(self.start) |
47 | 0 | } |
48 | | |
49 | 0 | fn pos(&self, key: usize) -> Option<usize> { |
50 | 0 | if self.start <= key && key < self.end { |
51 | 0 | Some(key - self.start) |
52 | | } else { |
53 | 0 | None |
54 | | } |
55 | 0 | } |
56 | | |
57 | 0 | fn key(&self, pos: usize) -> usize { |
58 | 0 | debug_assert!(pos < Keys::len(self)); |
59 | 0 | self.start + pos |
60 | 0 | } |
61 | | } |
62 | | |
63 | | /// Reads the concatenated value of a sequence of keys. |
64 | 0 | pub fn read(store: &Store<impl Storage>, keys: &impl Keys) -> StoreResult<Option<Vec<u8>>> { |
65 | 0 | let handles = get_handles(store, keys)?; |
66 | 0 | if handles.is_empty() { |
67 | 0 | return Ok(None); |
68 | 0 | } |
69 | 0 | let mut result = Vec::with_capacity(handles.len() * store.max_value_length()); |
70 | 0 | for handle in handles { |
71 | 0 | result.extend(handle.get_value(store)?); |
72 | | } |
73 | 0 | Ok(Some(result)) |
74 | 0 | } |
75 | | |
76 | | /// Reads a range from the concatenated value of a sequence of keys. |
77 | | /// |
78 | | /// This is equivalent to calling [`read`] then taking the range except that: |
79 | | /// - Only the needed chunks are read. |
80 | | /// - The range is truncated to fit in the value. |
81 | 0 | pub fn read_range( |
82 | 0 | store: &Store<impl Storage>, keys: &impl Keys, range: Range<usize>, |
83 | 0 | ) -> StoreResult<Option<Vec<u8>>> { |
84 | 0 | let range_len = match range.end.checked_sub(range.start) { |
85 | 0 | None => return Err(StoreError::InvalidArgument), |
86 | 0 | Some(x) => x, |
87 | | }; |
88 | 0 | let handles = get_handles(store, keys)?; |
89 | 0 | if handles.is_empty() { |
90 | 0 | return Ok(None); |
91 | 0 | } |
92 | 0 | let mut result = Vec::with_capacity(range_len); |
93 | 0 | let mut offset = 0; |
94 | 0 | for handle in handles { |
95 | 0 | let start = range.start.saturating_sub(offset); |
96 | 0 | let length = handle.get_length(store)?; |
97 | 0 | let end = core::cmp::min(range.end.saturating_sub(offset), length); |
98 | 0 | offset += length; |
99 | 0 | if start < end { |
100 | 0 | result.extend(&handle.get_value(store)?[start .. end]); |
101 | 0 | } |
102 | | } |
103 | 0 | Ok(Some(result)) |
104 | 0 | } |
105 | | |
106 | | /// Writes a value to a sequence of keys as chunks. |
107 | 0 | pub fn write(store: &mut Store<impl Storage>, keys: &impl Keys, value: &[u8]) -> StoreResult<()> { |
108 | 0 | let handles = get_handles(store, keys)?; |
109 | 0 | let keys_len = keys.len(); |
110 | 0 | let mut updates = Vec::with_capacity(keys_len); |
111 | 0 | let mut chunks = value.chunks(store.max_value_length()); |
112 | 0 | for pos in 0 .. keys_len { |
113 | 0 | let key = keys.key(pos); |
114 | 0 | match (handles.get(pos), chunks.next()) { |
115 | | // No existing handle and no new chunk: nothing to do. |
116 | 0 | (None, None) => (), |
117 | | // Existing handle and no new chunk: remove old handle. |
118 | 0 | (Some(_), None) => updates.push(StoreUpdate::Remove { key }), |
119 | | // Existing handle with same value as new chunk: nothing to do. |
120 | 0 | (Some(handle), Some(value)) if handle.get_value(store)? == value => (), |
121 | | // New chunk: Write (or overwrite) the new value. |
122 | 0 | (_, Some(value)) => updates.push(StoreUpdate::Insert { key, value }), |
123 | | } |
124 | | } |
125 | 0 | if chunks.next().is_some() { |
126 | | // The value is too long. |
127 | 0 | return Err(StoreError::InvalidArgument); |
128 | 0 | } |
129 | 0 | store.transaction(&updates) |
130 | 0 | } |
131 | | |
132 | | /// Deletes the value of a sequence of keys. |
133 | 0 | pub fn delete(store: &mut Store<impl Storage>, keys: &impl Keys) -> StoreResult<()> { |
134 | 0 | let updates: Vec<StoreUpdate<Vec<u8>>> = get_handles(store, keys)? |
135 | 0 | .iter() |
136 | 0 | .map(|handle| StoreUpdate::Remove { key: handle.get_key() }) |
137 | 0 | .collect(); |
138 | 0 | store.transaction(&updates) |
139 | 0 | } |
140 | | |
141 | | /// Returns the handles of a sequence of keys. |
142 | | /// |
143 | | /// The handles are truncated to the keys that are present. |
144 | 0 | fn get_handles(store: &Store<impl Storage>, keys: &impl Keys) -> StoreResult<Vec<StoreHandle>> { |
145 | 0 | let keys_len = keys.len(); |
146 | 0 | let mut handles: Vec<Option<StoreHandle>> = vec![None; keys_len]; |
147 | 0 | for handle in store.iter()? { |
148 | 0 | let handle = handle?; |
149 | 0 | let pos = match keys.pos(handle.get_key()) { |
150 | 0 | Some(pos) => pos, |
151 | 0 | None => continue, |
152 | | }; |
153 | 0 | if pos >= keys_len { |
154 | 0 | return Err(StoreError::InvalidArgument); |
155 | 0 | } |
156 | 0 | if let Some(old_handle) = &handles[pos] { |
157 | 0 | if old_handle.get_key() != handle.get_key() { |
158 | | // The user provided a non-injective `pos` function. |
159 | 0 | return Err(StoreError::InvalidArgument); |
160 | | } else { |
161 | 0 | return Err(StoreError::InvalidStorage); |
162 | | } |
163 | 0 | } |
164 | 0 | handles[pos] = Some(handle); |
165 | | } |
166 | 0 | let num_handles = handles.iter().filter(|x| x.is_some()).count(); |
167 | 0 | let mut result = Vec::with_capacity(num_handles); |
168 | 0 | for (i, handle) in handles.into_iter().enumerate() { |
169 | 0 | match (i < num_handles, handle) { |
170 | 0 | (true, Some(handle)) => result.push(handle), |
171 | 0 | (false, None) => (), |
172 | | // We should have `num_handles` Somes followed by Nones. |
173 | 0 | _ => return Err(StoreError::InvalidStorage), |
174 | | } |
175 | | } |
176 | 0 | Ok(result) |
177 | 0 | } |
178 | | |
179 | | #[cfg(test)] |
180 | | mod tests { |
181 | | use super::*; |
182 | | use crate::test::MINIMAL; |
183 | | |
184 | | #[test] |
185 | | fn read_empty_entry() { |
186 | | let store = MINIMAL.new_store(); |
187 | | assert_eq!(read(&store, &(0 .. 4)), Ok(None)); |
188 | | } |
189 | | |
190 | | #[test] |
191 | | fn read_single_chunk() { |
192 | | let mut store = MINIMAL.new_store(); |
193 | | let value = b"hello".to_vec(); |
194 | | assert_eq!(store.insert(0, &value), Ok(())); |
195 | | assert_eq!(read(&store, &(0 .. 4)), Ok(Some(value))); |
196 | | } |
197 | | |
198 | | #[test] |
199 | | fn read_multiple_chunks() { |
200 | | let mut store = MINIMAL.new_store(); |
201 | | let value: Vec<_> = (0 .. 60).collect(); |
202 | | assert_eq!(store.insert(0, &value[.. 52]), Ok(())); |
203 | | assert_eq!(store.insert(1, &value[52 ..]), Ok(())); |
204 | | assert_eq!(read(&store, &(0 .. 4)), Ok(Some(value))); |
205 | | } |
206 | | |
207 | | #[test] |
208 | | fn read_range_first_chunk() { |
209 | | let mut store = MINIMAL.new_store(); |
210 | | let value: Vec<_> = (0 .. 60).collect(); |
211 | | assert_eq!(store.insert(0, &value[.. 52]), Ok(())); |
212 | | assert_eq!(store.insert(1, &value[52 ..]), Ok(())); |
213 | | assert_eq!(read_range(&store, &(0 .. 4), 0 .. 10), Ok(Some((0 .. 10).collect()))); |
214 | | assert_eq!(read_range(&store, &(0 .. 4), 10 .. 20), Ok(Some((10 .. 20).collect()))); |
215 | | assert_eq!(read_range(&store, &(0 .. 4), 40 .. 52), Ok(Some((40 .. 52).collect()))); |
216 | | } |
217 | | |
218 | | #[test] |
219 | | fn read_range_second_chunk() { |
220 | | let mut store = MINIMAL.new_store(); |
221 | | let value: Vec<_> = (0 .. 60).collect(); |
222 | | assert_eq!(store.insert(0, &value[.. 52]), Ok(())); |
223 | | assert_eq!(store.insert(1, &value[52 ..]), Ok(())); |
224 | | assert_eq!(read_range(&store, &(0 .. 4), 52 .. 53), Ok(Some(vec![52]))); |
225 | | assert_eq!(read_range(&store, &(0 .. 4), 53 .. 54), Ok(Some(vec![53]))); |
226 | | assert_eq!(read_range(&store, &(0 .. 4), 59 .. 60), Ok(Some(vec![59]))); |
227 | | } |
228 | | |
229 | | #[test] |
230 | | fn read_range_both_chunks() { |
231 | | let mut store = MINIMAL.new_store(); |
232 | | let value: Vec<_> = (0 .. 60).collect(); |
233 | | assert_eq!(store.insert(0, &value[.. 52]), Ok(())); |
234 | | assert_eq!(store.insert(1, &value[52 ..]), Ok(())); |
235 | | assert_eq!(read_range(&store, &(0 .. 4), 40 .. 60), Ok(Some((40 .. 60).collect()))); |
236 | | assert_eq!(read_range(&store, &(0 .. 4), 0 .. 60), Ok(Some((0 .. 60).collect()))); |
237 | | } |
238 | | |
239 | | #[test] |
240 | | fn read_range_outside() { |
241 | | let mut store = MINIMAL.new_store(); |
242 | | let value: Vec<_> = (0 .. 60).collect(); |
243 | | assert_eq!(store.insert(0, &value[.. 52]), Ok(())); |
244 | | assert_eq!(store.insert(1, &value[52 ..]), Ok(())); |
245 | | assert_eq!(read_range(&store, &(0 .. 4), 40 .. 100), Ok(Some((40 .. 60).collect()))); |
246 | | assert_eq!(read_range(&store, &(0 .. 4), 60 .. 100), Ok(Some(vec![]))); |
247 | | } |
248 | | |
249 | | #[test] |
250 | | fn write_single_chunk() { |
251 | | let mut store = MINIMAL.new_store(); |
252 | | let value = b"hello".to_vec(); |
253 | | assert_eq!(write(&mut store, &(0 .. 4), &value), Ok(())); |
254 | | assert_eq!(store.find(0), Ok(Some(value))); |
255 | | assert_eq!(store.find(1), Ok(None)); |
256 | | assert_eq!(store.find(2), Ok(None)); |
257 | | assert_eq!(store.find(3), Ok(None)); |
258 | | } |
259 | | |
260 | | #[test] |
261 | | fn write_multiple_chunks() { |
262 | | let mut store = MINIMAL.new_store(); |
263 | | let value: Vec<_> = (0 .. 60).collect(); |
264 | | assert_eq!(write(&mut store, &(0 .. 4), &value), Ok(())); |
265 | | assert_eq!(store.find(0), Ok(Some((0 .. 52).collect()))); |
266 | | assert_eq!(store.find(1), Ok(Some((52 .. 60).collect()))); |
267 | | assert_eq!(store.find(2), Ok(None)); |
268 | | assert_eq!(store.find(3), Ok(None)); |
269 | | } |
270 | | |
271 | | #[test] |
272 | | fn overwrite_less_chunks() { |
273 | | let mut store = MINIMAL.new_store(); |
274 | | let value: Vec<_> = (0 .. 60).collect(); |
275 | | assert_eq!(store.insert(0, &value[.. 52]), Ok(())); |
276 | | assert_eq!(store.insert(1, &value[52 ..]), Ok(())); |
277 | | let value: Vec<_> = (42 .. 69).collect(); |
278 | | assert_eq!(write(&mut store, &(0 .. 4), &value), Ok(())); |
279 | | assert_eq!(store.find(0), Ok(Some((42 .. 69).collect()))); |
280 | | assert_eq!(store.find(1), Ok(None)); |
281 | | assert_eq!(store.find(2), Ok(None)); |
282 | | assert_eq!(store.find(3), Ok(None)); |
283 | | } |
284 | | |
285 | | #[test] |
286 | | fn overwrite_needed_chunks() { |
287 | | let mut store = MINIMAL.new_store(); |
288 | | let mut value: Vec<_> = (0 .. 60).collect(); |
289 | | assert_eq!(store.insert(0, &value[.. 52]), Ok(())); |
290 | | assert_eq!(store.insert(1, &value[52 ..]), Ok(())); |
291 | | // Current lifetime is 2 words of overhead (2 insert) and 60 bytes of data. |
292 | | let mut lifetime = 2 + 60 / 4; |
293 | | assert_eq!(store.lifetime().unwrap().used(), lifetime); |
294 | | // Update the value. |
295 | | value.extend(60 .. 80); |
296 | | assert_eq!(write(&mut store, &(0 .. 4), &value), Ok(())); |
297 | | // Added lifetime is 1 word of overhead (1 insert) and (80 - 52) bytes of data. |
298 | | lifetime += 1 + (80 - 52) / 4; |
299 | | assert_eq!(store.lifetime().unwrap().used(), lifetime); |
300 | | } |
301 | | |
302 | | #[test] |
303 | | fn delete_empty() { |
304 | | let mut store = MINIMAL.new_store(); |
305 | | assert_eq!(delete(&mut store, &(0 .. 4)), Ok(())); |
306 | | assert_eq!(store.find(0), Ok(None)); |
307 | | assert_eq!(store.find(1), Ok(None)); |
308 | | assert_eq!(store.find(2), Ok(None)); |
309 | | assert_eq!(store.find(3), Ok(None)); |
310 | | } |
311 | | |
312 | | #[test] |
313 | | fn delete_chunks() { |
314 | | let mut store = MINIMAL.new_store(); |
315 | | let value: Vec<_> = (0 .. 60).collect(); |
316 | | assert_eq!(store.insert(0, &value[.. 52]), Ok(())); |
317 | | assert_eq!(store.insert(1, &value[52 ..]), Ok(())); |
318 | | assert_eq!(delete(&mut store, &(0 .. 4)), Ok(())); |
319 | | assert_eq!(store.find(0), Ok(None)); |
320 | | assert_eq!(store.find(1), Ok(None)); |
321 | | assert_eq!(store.find(2), Ok(None)); |
322 | | assert_eq!(store.find(3), Ok(None)); |
323 | | } |
324 | | } |