Skip to main content

sled_overlay/
tree.rs

1/* This file is part of sled-overlay
2 *
3 * Copyright (C) 2023-2026 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(key)?;
145            cache.insert(key.into(), (previous, value.into()));
146        }
147
148        // Set removed keys
149        for key in state.removed.iter() {
150            // Grab each key last value, if it existed, otherwise
151            // use an empty value as its previous.
152            let previous = match tree.get(key)? {
153                Some(previous) => previous,
154                None => vec![].into(),
155            };
156            removed.insert(key.into(), previous);
157        }
158
159        Ok(Self { cache, removed })
160    }
161
162    /// Instantiate a new [`SledTreeOverlayStateDiff`], over the provided
163    /// [`sled::Tree`] that is being dropped. The diff will contain all
164    /// existing tree keys in its cache as inserts, representing the last tree state.
165    pub fn new_dropped(tree: &sled::Tree) -> Self {
166        let mut cache = BTreeMap::new();
167
168        // Insert all tree keys
169        for record in tree.iter() {
170            let (key, value) = record.unwrap();
171            cache.insert(key, (None, value));
172        }
173
174        Self {
175            cache,
176            removed: BTreeMap::new(),
177        }
178    }
179
180    /// Aggregate all the tree overlay state changes into
181    /// a [`sled::Batch`] ready for further operation.
182    /// If there are no changes, return `None`.
183    pub fn aggregate(&self) -> Option<sled::Batch> {
184        if self.cache.is_empty() && self.removed.is_empty() {
185            return None;
186        }
187
188        let mut batch = sled::Batch::default();
189
190        // This kind of first-insert-then-remove operation should be fine
191        // provided it's handled correctly in the above functions.
192        for (k, v) in self.cache.iter() {
193            batch.insert(k, v.1.clone());
194        }
195
196        for k in self.removed.keys() {
197            batch.remove(k);
198        }
199
200        Some(batch)
201    }
202
203    /// Aggregate all the current tree overlay state changes inverse
204    /// actions into a [`sled::Batch`] ready for further operation.
205    /// If there are no changes, return `None`.
206    pub fn revert(&self) -> Option<sled::Batch> {
207        if self.cache.is_empty() && self.removed.is_empty() {
208            return None;
209        }
210
211        let mut batch = sled::Batch::default();
212
213        // This kind of first-insert-then-remove operation should be fine
214        // provided it's handled correctly in the above functions.
215        for (k, v) in self.removed.iter() {
216            batch.insert(k, v.clone());
217        }
218
219        for (k, v) in self.cache.iter() {
220            // If key value has been modified, revert to previous one
221            if let Some(value) = &v.0 {
222                batch.insert(k, value.clone());
223                continue;
224            }
225            batch.remove(k);
226        }
227
228        Some(batch)
229    }
230
231    /// Produces a [`SledTreeOverlayStateDiff`] containing the inverse
232    /// changes from our own.
233    pub fn inverse(&self) -> Self {
234        let mut diff = Self::default();
235
236        // This kind of first-insert-then-remove operation should be fine
237        // provided it's handled correctly in the above functions.
238        for (k, v) in self.removed.iter() {
239            diff.cache.insert(k.clone(), (None, v.clone()));
240        }
241
242        for (k, v) in self.cache.iter() {
243            // If its value has been modified, flip it
244            if let Some(previous) = &v.0 {
245                diff.cache
246                    .insert(k.clone(), (Some(v.1.clone()), previous.clone()));
247                continue;
248            }
249            diff.removed.insert(k.clone(), v.1.clone());
250        }
251
252        diff
253    }
254
255    /// Remove provided tree overlay state changes from our own.
256    pub fn remove_diff(&mut self, other: &Self) {
257        for (k, v) in other.cache.iter() {
258            // Set as removed if its not in cache
259            let Some(values) = self.cache.get(k) else {
260                self.removed.insert(k.clone(), v.1.clone());
261                continue;
262            };
263
264            // Check if its value has been modified again
265            if v.1 != values.1 {
266                // Set previous value
267                self.cache
268                    .insert(k.clone(), (Some(v.1.clone()), values.1.clone()));
269                continue;
270            }
271
272            self.cache.remove(k);
273        }
274
275        for k in other.removed.keys() {
276            // Update cache key previous, if it exists
277            if let Some(values) = self.cache.get(k) {
278                self.cache.insert(k.clone(), (None, values.1.clone()));
279                continue;
280            }
281
282            self.removed.remove(k);
283        }
284    }
285
286    /// Update our cache key values to the ones in the provided
287    /// tree overlay state changes.
288    pub fn update_values(&mut self, other: &Self) {
289        for (k, v) in other.cache.iter() {
290            self.cache.insert(k.clone(), v.clone());
291        }
292
293        for k in other.removed.keys() {
294            self.cache.remove(k);
295        }
296    }
297}
298
299/// An overlay on top of a single [`sled::Tree`] instance.
300#[derive(Debug, Clone)]
301pub struct SledTreeOverlay {
302    /// The [`sled::Tree`] that is being overlayed.
303    pub tree: sled::Tree,
304    /// Current overlay cache state.
305    pub state: SledTreeOverlayState,
306    /// Checkpointed cache state to revert to.
307    checkpoint: SledTreeOverlayState,
308}
309
310impl SledTreeOverlay {
311    /// Instantiate a new [`SledTreeOverlay`] on top of a given [`sled::Tree`].
312    pub fn new(tree: &sled::Tree) -> Self {
313        Self {
314            tree: tree.clone(),
315            state: SledTreeOverlayState::new(),
316            checkpoint: SledTreeOverlayState::new(),
317        }
318    }
319
320    /// Returns `true` if the overlay contains a value for a specified key.
321    pub fn contains_key(&self, key: &[u8]) -> Result<bool, sled::Error> {
322        // First check if the key was removed in the overlay
323        let key = IVec::from(key);
324        if self.state.removed.contains(&key) {
325            return Ok(false);
326        }
327
328        // Then check the cache and the main tree
329        if self.state.cache.contains_key(&key) || self.tree.contains_key(key)? {
330            return Ok(true);
331        }
332
333        Ok(false)
334    }
335
336    /// Returns `true` if the overlay is empty.
337    pub fn is_empty(&self) -> Result<bool, sled::Error> {
338        // Keep a counter of all elements
339        let mut counter: i64 = 0;
340
341        // Add existing keys
342        counter += self.tree.len() as i64;
343
344        // Add new keys
345        for key in self.state.cache.keys() {
346            if !self.tree.contains_key(key)? {
347                counter += 1;
348            }
349        }
350
351        // Subtract removed keys
352        counter -= self.state.removed.len() as i64;
353
354        Ok(counter <= 0)
355    }
356
357    /// Returns last key and value from the overlay or `None` if its empty,
358    /// based on the `Ord` implementation for `Vec<u8>`.
359    pub fn last(&self) -> Result<Option<(IVec, IVec)>, sled::Error> {
360        // If both main tree and cache are empty, return None
361        if self.tree.is_empty() && self.state.cache.is_empty() {
362            return Ok(None);
363        }
364
365        // Grab main tree last record
366        let tree_last = self.tree.last()?;
367
368        // If cache has no records, main tree last exists
369        if self.state.cache.is_empty() {
370            // We can safely unwrap here since main tree is not
371            // empty, as we have already checked if both main
372            // tree and cache are empty.
373            let record = tree_last.unwrap();
374
375            // Check if record is removed
376            if self.state.removed.contains(&record.0) {
377                // Find last existing record
378                let mut key = record.0.clone();
379                while let Some(record) = self.tree.get_lt(key)? {
380                    // Check if record is removed
381                    if self.state.removed.contains(&record.0) {
382                        key = record.0;
383                        continue;
384                    }
385                    // Return it
386                    return Ok(Some((record.0.clone(), record.1.clone())));
387                }
388
389                // Return None if no records exist
390                return Ok(None);
391            }
392
393            // Return it
394            return Ok(Some((record.0.clone(), record.1.clone())));
395        }
396
397        // Grab cache last record.
398        // We can safely unwrap here as we checked if the cache is
399        // empty on the previous step.
400        let cache_last = self.state.cache.last_key_value().unwrap();
401
402        // Find the main tree last existing record, compare it with the
403        // cache last record, and return it if it's not removed
404        if let Some(tree_last) = tree_last {
405            if cache_last.0 < &tree_last.0 && !self.state.removed.contains(&tree_last.0) {
406                return Ok(Some((tree_last.0.clone(), tree_last.1.clone())));
407            }
408
409            let mut key = tree_last.0.clone();
410            while let Some(record) = self.tree.get_lt(key)? {
411                // Break if we reach the cache key position
412                if cache_last.0 >= &record.0 {
413                    break;
414                }
415
416                // Check if record is removed
417                if !self.state.removed.contains(&record.0) {
418                    return Ok(Some((record.0.clone(), record.1.clone())));
419                }
420
421                key = record.0;
422            }
423        }
424
425        // Return the cache last record
426        Ok(Some((cache_last.0.clone(), cache_last.1.clone())))
427    }
428
429    /// Retrieve a value from the overlay if it exists.
430    pub fn get(&self, key: &[u8]) -> Result<Option<IVec>, sled::Error> {
431        // First check if the key was removed in the overlay
432        let key = IVec::from(key);
433        if self.state.removed.contains(&key) {
434            return Ok(None);
435        }
436
437        // Then check the cache
438        if let Some(v) = self.state.cache.get(&key) {
439            return Ok(Some(v.clone()));
440        }
441
442        // And finally the main tree
443        self.tree.get(key)
444    }
445
446    /// Insert a key to a new value, returning the last value if it was set.
447    pub fn insert(&mut self, key: &[u8], value: &[u8]) -> Result<Option<IVec>, sled::Error> {
448        // Insert the value into the cache. We then optionally add the previous value
449        // into `prev`.
450        let mut prev: Option<IVec> = self.state.cache.insert(key.into(), value.into());
451
452        // In case this key was previously removed from the cache, we have to
453        // delete it from the `removed` set.
454        let key = IVec::from(key);
455        if self.state.removed.contains(&key) {
456            self.state.removed.remove(&key);
457            // And in that case, a previous value isn't supposed to exist
458            return Ok(None);
459        }
460
461        // If cache didn't contain this key previously, and it wasn't removed
462        // either, then check if it's in the main tree.
463        if prev.is_none() {
464            prev = self.tree.get(key)?;
465        }
466
467        Ok(prev)
468    }
469
470    /// Delete a value, if it exists, returning the old value.
471    pub fn remove(&mut self, key: &[u8]) -> Result<Option<IVec>, sled::Error> {
472        // If it was previously removed, we can just return None
473        let key = IVec::from(key);
474        if self.state.removed.contains(&key) {
475            return Ok(None);
476        }
477
478        // Attempt to remove from cache, and if it wasn't in the cache before,
479        // we have to get the previous value from the sled tree:
480        let mut prev: Option<IVec> = self.state.cache.remove(&key);
481        if prev.is_none() {
482            prev = self.tree.get(&key)?;
483        }
484
485        // Previous value must existed
486        if prev.is_none() {
487            return Err(sled::Error::CollectionNotFound(key));
488        }
489
490        // Mark the key as removed
491        self.state.removed.insert(key);
492
493        Ok(prev)
494    }
495
496    /// Removes all values from the cache and marks all tree records as
497    /// removed.
498    pub fn clear(&mut self) -> Result<(), sled::Error> {
499        // Retrieve all db's keys to mark them as removed
500        let removed_keys = self
501            .tree
502            .iter()
503            .keys()
504            .collect::<Result<BTreeSet<IVec>, sled::Error>>()?;
505
506        // Clear state
507        self.state.cache = BTreeMap::new();
508        self.state.removed = removed_keys;
509
510        Ok(())
511    }
512
513    /// Aggregate all the current overlay changes into a [`sled::Batch`] ready for
514    /// further operation. If there are no changes, return `None`.
515    pub fn aggregate(&self) -> Option<sled::Batch> {
516        self.state.aggregate()
517    }
518
519    /// Checkpoint current cache state so we can revert to it, if needed.
520    pub fn checkpoint(&mut self) {
521        self.checkpoint = self.state.clone();
522    }
523
524    /// Revert to current cache state checkpoint.
525    pub fn revert_to_checkpoint(&mut self) {
526        self.state = self.checkpoint.clone();
527    }
528
529    /// Calculate differences from provided overlay state changes
530    /// sequence. This can be used when we want to keep track of
531    /// consecutive individual changes performed over the current
532    /// overlay state. If the sequence is empty, current state
533    /// is returned as the diff.
534    pub fn diff(
535        &self,
536        sequence: &[SledTreeOverlayStateDiff],
537    ) -> Result<SledTreeOverlayStateDiff, sled::Error> {
538        // Grab current state
539        let mut current = SledTreeOverlayStateDiff::new(&self.tree, &self.state)?;
540
541        // Remove provided diffs sequence
542        for diff in sequence {
543            current.remove_diff(diff);
544        }
545
546        Ok(current)
547    }
548
549    /// Add provided tree overlay state changes from our own.
550    pub fn add_diff(&mut self, diff: &SledTreeOverlayStateDiff) {
551        self.state.add_diff(diff)
552    }
553
554    /// Remove provided tree overlay state changes from our own.
555    pub fn remove_diff(&mut self, diff: &SledTreeOverlayStateDiff) {
556        self.state.remove_diff(diff)
557    }
558
559    /// Immutably iterate through the tree overlay.
560    pub fn iter(&self) -> SledTreeOverlayIter<'_> {
561        SledTreeOverlayIter::new(self)
562    }
563}
564
565/// Immutable iterator of a [`SledTreeOverlay`].
566pub struct SledTreeOverlayIter<'a> {
567    // Reference to the tree overlay.
568    overlay: &'a SledTreeOverlay,
569    // Iterator over [`sled::Tree`] keys that is being overlayed.
570    tree_iter: Peekable<Iter>,
571    // Iterator over the overlay's chache keys.
572    cache_iter: Peekable<Keys<'a, IVec, IVec>>,
573}
574
575impl<'a> SledTreeOverlayIter<'a> {
576    fn new(overlay: &'a SledTreeOverlay) -> Self {
577        Self {
578            overlay,
579            tree_iter: overlay.tree.iter().peekable(),
580            cache_iter: overlay.state.cache.keys().peekable(),
581        }
582    }
583}
584
585impl Iterator for SledTreeOverlayIter<'_> {
586    type Item = Result<(IVec, IVec), sled::Error>;
587
588    fn next(&mut self) -> Option<Self::Item> {
589        // First we peek over the next tree key
590        let peek1 = self.tree_iter.peek();
591
592        // Check if a sled error occured
593        if let Some(Err(e)) = peek1 {
594            return Some(Err(e.clone()));
595        }
596
597        // Peek over the next cache key
598        let peek2 = self.cache_iter.peek();
599
600        // Find the next key we have to grab,
601        // and which iterator to advance.
602        let mut advance_iter: u8 = 0;
603        let next_key = match (peek1, peek2) {
604            (Some(k1), Some(&k2)) => {
605                // Its safe to unwrap here since we already checked for errors
606                let (k1, _) = k1.as_ref().unwrap();
607                match k1.cmp(k2) {
608                    Ordering::Equal => Some(k1.clone()),
609                    Ordering::Greater => {
610                        advance_iter = 2;
611                        Some(k2.clone())
612                    }
613                    Ordering::Less => {
614                        advance_iter = 1;
615                        Some(k1.clone())
616                    }
617                }
618            }
619            (Some(k1), None) => {
620                // Its safe to unwrap here since we already checked for errors
621                let (k1, _) = k1.as_ref().unwrap();
622                advance_iter = 1;
623                Some(k1.clone())
624            }
625            (None, Some(&k2)) => {
626                advance_iter = 2;
627                Some(k2.clone())
628            }
629            (None, None) => None,
630        };
631
632        // Check if we have a key to grab
633        let next_key = next_key?;
634
635        // Advance the corresponding iterator
636        match advance_iter {
637            1 => {
638                self.tree_iter.next();
639            }
640            2 => {
641                self.cache_iter.next();
642            }
643            _ => {
644                self.tree_iter.next();
645                self.cache_iter.next();
646            }
647        }
648
649        // Grab the next key value from the overlay
650        match self.overlay.get(&next_key) {
651            Ok(next_value) => match next_value {
652                Some(next_value) => Some(Ok((next_key, next_value))),
653                // If the value doesn't exist, it means it's in the
654                // removed set, so we advance the iterator.
655                None => self.next(),
656            },
657            Err(e) => Some(Err(e)),
658        }
659    }
660}
661
662impl FusedIterator for SledTreeOverlayIter<'_> {}
663
664/// Define fusion iteration behavior, allowing
665/// us to use the [`SledTreeOverlayIter`] iterator in
666/// loops directly, without using .iter() method
667/// of [`SledTreeOverlay`].
668impl<'a> IntoIterator for &'a SledTreeOverlay {
669    type Item = Result<(IVec, IVec), sled::Error>;
670
671    type IntoIter = SledTreeOverlayIter<'a>;
672
673    fn into_iter(self) -> Self::IntoIter {
674        self.iter()
675    }
676}