sled_overlay/tree.rs
1/* This file is part of sled-overlay
2 *
3 * Copyright (C) 2023-2024 Dyne.org foundation
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU Affero General Public License as
7 * published by the Free Software Foundation, either version 3 of the
8 * License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program. If not, see <https://www.gnu.org/licenses/>.
17 */
18
19use std::{
20 cmp::Ordering,
21 collections::{btree_map::Keys, BTreeMap, BTreeSet},
22 iter::{FusedIterator, Peekable},
23};
24
25use sled::{IVec, Iter};
26
27/// Struct representing [`SledTreeOverlay`] cache state.
28#[derive(Debug, Default, Clone, PartialEq)]
29pub struct SledTreeOverlayState {
30 /// The cache is the actual overlayed data represented as a [`BTreeMap`].
31 pub cache: BTreeMap<IVec, IVec>,
32 /// In `removed`, we keep track of keys that were removed in the overlay.
33 pub removed: BTreeSet<IVec>,
34}
35
36impl SledTreeOverlayState {
37 /// Instantiate a new [`SledTreeOverlayState`].
38 pub fn new() -> Self {
39 Self {
40 cache: BTreeMap::new(),
41 removed: BTreeSet::new(),
42 }
43 }
44
45 /// Aggregate all the current tree overlay state changes into
46 /// a [`sled::Batch`] ready for further operation.
47 /// If there are no changes, return `None`.
48 pub fn aggregate(&self) -> Option<sled::Batch> {
49 if self.cache.is_empty() && self.removed.is_empty() {
50 return None;
51 }
52
53 let mut batch = sled::Batch::default();
54
55 // This kind of first-insert-then-remove operation should be fine
56 // provided it's handled correctly in the above functions.
57 for (k, v) in self.cache.iter() {
58 batch.insert(k, v);
59 }
60
61 for k in self.removed.iter() {
62 batch.remove(k);
63 }
64
65 Some(batch)
66 }
67
68 /// Add provided tree overlay state changes to our own.
69 pub fn add_diff(&mut self, diff: &SledTreeOverlayStateDiff) {
70 // Add all new keys into cache
71 for (k, v) in diff.cache.iter() {
72 self.removed.remove(k);
73 self.cache.insert(k.clone(), v.1.clone());
74 }
75
76 // Remove dropped keys
77 for k in diff.removed.keys() {
78 self.cache.remove(k);
79 self.removed.insert(k.clone());
80 }
81 }
82
83 /// Remove provided tree overlay state changes from our own.
84 pub fn remove_diff(&mut self, diff: &SledTreeOverlayStateDiff) {
85 for (k, v) in diff.cache.iter() {
86 // Skip if its not in cache
87 let Some(value) = self.cache.get(k) else {
88 continue;
89 };
90
91 // Check if its value has been modified again
92 if v.1 != value {
93 continue;
94 }
95
96 self.cache.remove(k);
97 }
98
99 for k in diff.removed.keys() {
100 self.removed.remove(k);
101 }
102 }
103}
104
105impl From<&SledTreeOverlayStateDiff> for SledTreeOverlayState {
106 fn from(diff: &SledTreeOverlayStateDiff) -> Self {
107 let mut cache = BTreeMap::new();
108 let mut removed = BTreeSet::new();
109
110 for (key, value) in diff.cache.iter() {
111 cache.insert(key.clone(), value.1.clone());
112 }
113
114 for key in diff.removed.keys() {
115 removed.insert(key.clone());
116 }
117
118 Self { cache, removed }
119 }
120}
121
122/// Auxilliary struct representing a [`SledTreeOverlayState`] diff log.
123#[derive(Debug, Default, Clone, PartialEq)]
124pub struct SledTreeOverlayStateDiff {
125 /// Inserted data represented as a [`BTreeMap`].
126 /// The value contains both the previous key value(if it existed), along
127 /// with the new one.
128 pub cache: BTreeMap<IVec, (Option<IVec>, IVec)>,
129 /// In `removed`, we keep track of keys that were removed in the overlay,
130 /// along with their value.
131 pub removed: BTreeMap<IVec, IVec>,
132}
133
134impl SledTreeOverlayStateDiff {
135 /// Instantiate a new [`SledTreeOverlayStateDiff`], over the provided
136 /// [`sled::Tree`] that is being overlayed.
137 pub fn new(tree: &sled::Tree, state: &SledTreeOverlayState) -> Result<Self, sled::Error> {
138 let mut cache = BTreeMap::new();
139 let mut removed = BTreeMap::new();
140
141 // Set inserted keys
142 for (key, value) in state.cache.iter() {
143 // Grab each key previous value, if it existed
144 let previous = tree.get::<IVec>(key.into())?;
145 cache.insert(key.into(), (previous, value.into()));
146 }
147
148 // Set removed keys, if they exist
149 for key in state.removed.iter() {
150 if let Some(previous) = tree.get(key)? {
151 removed.insert(key.into(), previous);
152 };
153 }
154
155 Ok(Self { cache, removed })
156 }
157
158 /// Instantiate a new [`SledTreeOverlayStateDiff`], over the provided
159 /// [`sled::Tree`] that is being dropped. The diff will contain all
160 /// existing tree keys in its cache as inserts, representing the last tree state.
161 pub fn new_dropped(tree: &sled::Tree) -> Self {
162 let mut cache = BTreeMap::new();
163
164 // Insert all tree keys
165 for record in tree.iter() {
166 let (key, value) = record.unwrap();
167 cache.insert(key, (None, value));
168 }
169
170 Self {
171 cache,
172 removed: BTreeMap::new(),
173 }
174 }
175
176 /// Aggregate all the tree overlay state changes into
177 /// a [`sled::Batch`] ready for further operation.
178 /// If there are no changes, return `None`.
179 pub fn aggregate(&self) -> Option<sled::Batch> {
180 if self.cache.is_empty() && self.removed.is_empty() {
181 return None;
182 }
183
184 let mut batch = sled::Batch::default();
185
186 // This kind of first-insert-then-remove operation should be fine
187 // provided it's handled correctly in the above functions.
188 for (k, v) in self.cache.iter() {
189 batch.insert(k, v.1.clone());
190 }
191
192 for k in self.removed.keys() {
193 batch.remove(k);
194 }
195
196 Some(batch)
197 }
198
199 /// Aggregate all the current tree overlay state changes inverse
200 /// actions into a [`sled::Batch`] ready for further operation.
201 /// If there are no changes, return `None`.
202 pub fn revert(&self) -> Option<sled::Batch> {
203 if self.cache.is_empty() && self.removed.is_empty() {
204 return None;
205 }
206
207 let mut batch = sled::Batch::default();
208
209 // This kind of first-insert-then-remove operation should be fine
210 // provided it's handled correctly in the above functions.
211 for (k, v) in self.removed.iter() {
212 batch.insert(k, v.clone());
213 }
214
215 for (k, v) in self.cache.iter() {
216 // If key value has been modified, revert to previous one
217 if let Some(value) = &v.0 {
218 batch.insert(k, value.clone());
219 continue;
220 }
221 batch.remove(k);
222 }
223
224 Some(batch)
225 }
226
227 /// Produces a [`SledTreeOverlayStateDiff`] containing the inverse
228 /// changes from our own.
229 pub fn inverse(&self) -> Self {
230 let mut diff = Self::default();
231
232 // This kind of first-insert-then-remove operation should be fine
233 // provided it's handled correctly in the above functions.
234 for (k, v) in self.removed.iter() {
235 diff.cache.insert(k.clone(), (None, v.clone()));
236 }
237
238 for (k, v) in self.cache.iter() {
239 // If its value has been modified, flip it
240 if let Some(previous) = &v.0 {
241 diff.cache
242 .insert(k.clone(), (Some(v.1.clone()), previous.clone()));
243 continue;
244 }
245 diff.removed.insert(k.clone(), v.1.clone());
246 }
247
248 diff
249 }
250
251 /// Remove provided tree overlay state changes from our own.
252 pub fn remove_diff(&mut self, other: &Self) {
253 for (k, v) in other.cache.iter() {
254 // Set as removed if its not in cache
255 let Some(values) = self.cache.get(k) else {
256 self.removed.insert(k.clone(), v.1.clone());
257 continue;
258 };
259
260 // Check if its value has been modified again
261 if v.1 != values.1 {
262 // Set previous value
263 self.cache
264 .insert(k.clone(), (Some(v.1.clone()), values.1.clone()));
265 continue;
266 }
267
268 self.cache.remove(k);
269 }
270
271 for k in other.removed.keys() {
272 // Update cache key previous, if it exits
273 if let Some(values) = self.cache.get(k) {
274 self.cache.insert(k.clone(), (None, values.1.clone()));
275 continue;
276 }
277
278 self.removed.remove(k);
279 }
280 }
281
282 /// Update our cache key values to the ones in the provided
283 /// tree overlay state changes.
284 pub fn update_values(&mut self, other: &Self) {
285 for (k, v) in other.cache.iter() {
286 self.cache.insert(k.clone(), v.clone());
287 }
288
289 for k in other.removed.keys() {
290 self.cache.remove(k);
291 }
292 }
293}
294
295/// An overlay on top of a single [`sled::Tree`] instance.
296#[derive(Debug, Clone)]
297pub struct SledTreeOverlay {
298 /// The [`sled::Tree`] that is being overlayed.
299 pub tree: sled::Tree,
300 /// Current overlay cache state.
301 pub state: SledTreeOverlayState,
302 /// Checkpointed cache state to revert to.
303 checkpoint: SledTreeOverlayState,
304}
305
306impl SledTreeOverlay {
307 /// Instantiate a new [`SledTreeOverlay`] on top of a given [`sled::Tree`].
308 pub fn new(tree: &sled::Tree) -> Self {
309 Self {
310 tree: tree.clone(),
311 state: SledTreeOverlayState::new(),
312 checkpoint: SledTreeOverlayState::new(),
313 }
314 }
315
316 /// Returns `true` if the overlay contains a value for a specified key.
317 pub fn contains_key(&self, key: &[u8]) -> Result<bool, sled::Error> {
318 // First check if the key was removed in the overlay
319 if self.state.removed.contains::<IVec>(&key.into()) {
320 return Ok(false);
321 }
322
323 // Then check the cache and the main tree
324 if self.state.cache.contains_key::<IVec>(&key.into()) || self.tree.contains_key(key)? {
325 return Ok(true);
326 }
327
328 Ok(false)
329 }
330
331 /// Returns `true` if the overlay is empty.
332 pub fn is_empty(&self) -> bool {
333 // Keep a counter of all elements
334 let mut counter: i64 = 0;
335
336 // Add existing keys
337 counter += self.tree.len() as i64;
338
339 // Add new keys
340 counter += self.state.cache.len() as i64;
341
342 // Subtract removed keys
343 counter -= self.state.removed.len() as i64;
344
345 counter <= 0
346 }
347
348 /// Returns last key and value from the overlay or `None` if its empty,
349 /// based on the `Ord` implementation for `Vec<u8>`.
350 pub fn last(&self) -> Result<Option<(IVec, IVec)>, sled::Error> {
351 // If both main tree and cache are empty, return None
352 if self.tree.is_empty() && self.state.cache.is_empty() {
353 return Ok(None);
354 }
355
356 // Grab main tree last record
357 let tree_last = self.tree.last()?;
358
359 // If cache has no records, main tree last exists
360 if self.state.cache.is_empty() {
361 // We can safely unwrap here since main tree is not
362 // empty, as we have already checked if both main
363 // tree and cache are empty.
364 let record = tree_last.unwrap();
365
366 // Check if record is removed
367 if self.state.removed.contains(&record.0) {
368 // Find last existing record
369 let mut key = record.0.clone();
370 while let Some(record) = self.tree.get_lt(key)? {
371 // Check if record is removed
372 if self.state.removed.contains(&record.0) {
373 key = record.0;
374 continue;
375 }
376 // Return it
377 return Ok(Some((record.0.clone(), record.1.clone())));
378 }
379
380 // Return None if no records exist
381 return Ok(None);
382 }
383
384 // Return it
385 return Ok(Some((record.0.clone(), record.1.clone())));
386 }
387
388 // Grab cache last record.
389 // We can safely unwrap here as we checked if the cache is
390 // empty on the previous step.
391 let cache_last = self.state.cache.last_key_value().unwrap();
392
393 // If the main tree has a last record, compare it with the cache
394 // last record, and return it if it's not removed
395 if let Some(tree_last) = tree_last {
396 if cache_last.0 < &tree_last.0 && !self.state.removed.contains(&tree_last.0) {
397 return Ok(Some((tree_last.0.clone(), tree_last.1.clone())));
398 }
399 }
400
401 // Return the cache last record
402 Ok(Some((cache_last.0.clone(), cache_last.1.clone())))
403 }
404
405 /// Retrieve a value from the overlay if it exists.
406 pub fn get(&self, key: &[u8]) -> Result<Option<IVec>, sled::Error> {
407 // First check if the key was removed in the overlay
408 if self.state.removed.contains::<IVec>(&key.into()) {
409 return Ok(None);
410 }
411
412 // Then check the cache
413 if let Some(v) = self.state.cache.get::<IVec>(&key.into()) {
414 return Ok(Some(v.clone()));
415 }
416
417 // And finally the main tree
418 self.tree.get(key)
419 }
420
421 /// Insert a key to a new value, returning the last value if it was set.
422 pub fn insert(&mut self, key: &[u8], value: &[u8]) -> Result<Option<IVec>, sled::Error> {
423 // Insert the value into the cache. We then optionally add the previous value
424 // into `prev`.
425 let mut prev: Option<IVec> = self.state.cache.insert(key.into(), value.into());
426
427 // In case this key was previously removed from the cache, we have to
428 // delete it from the `removed` set.
429 if self.state.removed.contains::<IVec>(&key.into()) {
430 self.state.removed.remove(key);
431 // And in that case, a previous value isn't supposed to exist
432 return Ok(None);
433 }
434
435 // If cache didn't contain this key previously, and it wasn't removed
436 // either, then check if it's in the main tree.
437 if prev.is_none() {
438 prev = self.tree.get::<IVec>(key.into())?;
439 }
440
441 Ok(prev)
442 }
443
444 /// Delete a value, if it exists, returning the old value.
445 pub fn remove(&mut self, key: &[u8]) -> Result<Option<IVec>, sled::Error> {
446 // If it was previously removed, we can just return None
447 if self.state.removed.contains::<IVec>(&key.into()) {
448 return Ok(None);
449 }
450
451 // Attempt to remove from cache, and if it wasn't in the cache before,
452 // we have to get the previous value from the sled tree:
453 let mut prev: Option<IVec> = self.state.cache.remove::<IVec>(&key.into());
454 if prev.is_none() {
455 prev = self.tree.get(key)?;
456 }
457
458 // Previous value must existed
459 if prev.is_none() {
460 return Err(sled::Error::CollectionNotFound(key.into()));
461 }
462
463 // Mark the key as removed
464 self.state.removed.insert(key.into());
465
466 Ok(prev)
467 }
468
469 /// Removes all values from the cache and marks all tree records as
470 /// removed.
471 pub fn clear(&mut self) -> Result<(), sled::Error> {
472 // Clear state
473 self.state.cache = BTreeMap::new();
474
475 // Mark all the db's keys as removed
476 self.state.removed = self
477 .tree
478 .iter()
479 .keys()
480 .collect::<Result<BTreeSet<IVec>, sled::Error>>()?;
481
482 Ok(())
483 }
484
485 /// Aggregate all the current overlay changes into a [`sled::Batch`] ready for
486 /// further operation. If there are no changes, return `None`.
487 pub fn aggregate(&self) -> Option<sled::Batch> {
488 self.state.aggregate()
489 }
490
491 /// Checkpoint current cache state so we can revert to it, if needed.
492 pub fn checkpoint(&mut self) {
493 self.checkpoint = self.state.clone();
494 }
495
496 /// Revert to current cache state checkpoint.
497 pub fn revert_to_checkpoint(&mut self) {
498 self.state = self.checkpoint.clone();
499 }
500
501 /// Calculate differences from provided overlay state changes
502 /// sequence. This can be used when we want to keep track of
503 /// consecutive individual changes performed over the current
504 /// overlay state. If the sequence is empty, current state
505 /// is returned as the diff.
506 pub fn diff(
507 &self,
508 sequence: &[SledTreeOverlayStateDiff],
509 ) -> Result<SledTreeOverlayStateDiff, sled::Error> {
510 // Grab current state
511 let mut current = SledTreeOverlayStateDiff::new(&self.tree, &self.state)?;
512
513 // Remove provided diffs sequence
514 for diff in sequence {
515 current.remove_diff(diff);
516 }
517
518 Ok(current)
519 }
520
521 /// Add provided tree overlay state changes from our own.
522 pub fn add_diff(&mut self, diff: &SledTreeOverlayStateDiff) {
523 self.state.add_diff(diff)
524 }
525
526 /// Remove provided tree overlay state changes from our own.
527 pub fn remove_diff(&mut self, diff: &SledTreeOverlayStateDiff) {
528 self.state.remove_diff(diff)
529 }
530
531 /// Immutably iterate through the tree overlay.
532 pub fn iter(&self) -> SledTreeOverlayIter<'_> {
533 SledTreeOverlayIter::new(self)
534 }
535}
536
537/// Immutable iterator of a [`SledTreeOverlay`].
538pub struct SledTreeOverlayIter<'a> {
539 // Reference to the tree overlay.
540 overlay: &'a SledTreeOverlay,
541 // Iterator over [`sled::Tree`] keys that is being overlayed.
542 tree_iter: Peekable<Iter>,
543 // Iterator over the overlay's chache keys.
544 cache_iter: Peekable<Keys<'a, IVec, IVec>>,
545}
546
547impl<'a> SledTreeOverlayIter<'a> {
548 fn new(overlay: &'a SledTreeOverlay) -> Self {
549 Self {
550 overlay,
551 tree_iter: overlay.tree.iter().peekable(),
552 cache_iter: overlay.state.cache.keys().peekable(),
553 }
554 }
555}
556
557impl Iterator for SledTreeOverlayIter<'_> {
558 type Item = Result<(IVec, IVec), sled::Error>;
559
560 fn next(&mut self) -> Option<Self::Item> {
561 // First we peek over the next tree key
562 let peek1 = self.tree_iter.peek();
563
564 // Check if a sled error occured
565 if let Some(Err(e)) = peek1 {
566 return Some(Err(e.clone()));
567 }
568
569 // Peek over the next cache key
570 let peek2 = self.cache_iter.peek();
571
572 // Find the next key we have to grab,
573 // and which iterator to advance.
574 let mut advance_iter: u8 = 0;
575 let next_key = match (peek1, peek2) {
576 (Some(k1), Some(&k2)) => {
577 // Its safe to unwrap here since we already checked for errors
578 let (k1, _) = k1.as_ref().unwrap();
579 match k1.cmp(k2) {
580 Ordering::Equal => Some(k1.clone()),
581 Ordering::Greater => {
582 advance_iter = 2;
583 Some(k2.clone())
584 }
585 Ordering::Less => {
586 advance_iter = 1;
587 Some(k1.clone())
588 }
589 }
590 }
591 (Some(k1), None) => {
592 // Its safe to unwrap here since we already checked for errors
593 let (k1, _) = k1.as_ref().unwrap();
594 advance_iter = 1;
595 Some(k1.clone())
596 }
597 (None, Some(&k2)) => {
598 advance_iter = 2;
599 Some(k2.clone())
600 }
601 (None, None) => None,
602 };
603
604 // Check if we have a key to grab
605 let next_key = next_key?;
606
607 // Advance the corresponding iterator
608 match advance_iter {
609 1 => {
610 self.tree_iter.next();
611 }
612 2 => {
613 self.cache_iter.next();
614 }
615 _ => {
616 self.tree_iter.next();
617 self.cache_iter.next();
618 }
619 }
620
621 // Grab the next key value from the overlay
622 match self.overlay.get(&next_key) {
623 Ok(next_value) => match next_value {
624 Some(next_value) => Some(Ok((next_key, next_value))),
625 // If the value doesn't exist, it means it's in the
626 // removed set, so we advance the iterator.
627 None => self.next(),
628 },
629 Err(e) => Some(Err(e)),
630 }
631 }
632}
633
634impl FusedIterator for SledTreeOverlayIter<'_> {}
635
636/// Define fusion iteration behavior, allowing
637/// us to use the [`SledTreeOverlayIter`] iterator in
638/// loops directly, without using .iter() method
639/// of [`SledTreeOverlay`].
640impl<'a> IntoIterator for &'a SledTreeOverlay {
641 type Item = Result<(IVec, IVec), sled::Error>;
642
643 type IntoIter = SledTreeOverlayIter<'a>;
644
645 fn into_iter(self) -> Self::IntoIter {
646 self.iter()
647 }
648}