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