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}