Skip to content

Commit ced9667

Browse files
gabriele-0201rphmeier
authored andcommitted
fix: properly handle deletions within overlays
1 parent 543ed55 commit ced9667

File tree

2 files changed

+123
-15
lines changed

2 files changed

+123
-15
lines changed

nomt/src/merkle/seek.rs

Lines changed: 31 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,7 @@ impl SeekRequest {
192192

193193
fn continue_leaf_fetch<H: HashAlgorithm>(&mut self, leaf: Option<LeafNodeRef>) {
194194
let RequestState::FetchingLeaf {
195+
ref mut overlay_deletions,
195196
ref mut beatree_iterator,
196197
..
197198
} = self.state
@@ -203,13 +204,24 @@ impl SeekRequest {
203204
beatree_iterator.provide_leaf(leaf);
204205
}
205206

206-
let (key, value_hash) = match beatree_iterator.next() {
207-
None => panic!("leaf must exist position={}", self.position.path()),
208-
Some(IterOutput::Blocked) => return,
209-
Some(IterOutput::Item(key, value)) => {
210-
(key, H::hash_value(&value)) // hash
207+
let mut deletions_idx = 0;
208+
let (key, value_hash) = loop {
209+
match beatree_iterator.next() {
210+
None => panic!("leaf must exist position={}", self.position.path()),
211+
Some(IterOutput::Blocked) => {
212+
overlay_deletions.drain(..deletions_idx);
213+
return;
214+
}
215+
Some(IterOutput::Item(key, _value))
216+
if deletions_idx < overlay_deletions.len()
217+
&& overlay_deletions[deletions_idx] == key =>
218+
{
219+
deletions_idx += 1;
220+
continue;
221+
}
222+
Some(IterOutput::Item(key, value)) => break (key, H::hash_value(&value)),
223+
Some(IterOutput::OverflowItem(key, value_hash, _)) => break (key, value_hash),
211224
}
212-
Some(IterOutput::OverflowItem(key, value_hash, _)) => (key, value_hash),
213225
};
214226

215227
self.state = RequestState::Completed(Some(trie::LeafData {
@@ -351,6 +363,7 @@ enum RequestState {
351363
Seeking,
352364
// Fetching one leaf
353365
FetchingLeaf {
366+
overlay_deletions: Vec<KeyPath>,
354367
beatree_iterator: BeatreeIterator,
355368
needed_leaves: NeededLeavesIter,
356369
},
@@ -373,16 +386,18 @@ impl RequestState {
373386
) -> Self {
374387
let (start, end) = range_bounds(pos.raw_path(), pos.depth() as usize);
375388

376-
// First see if the item is present within the overlay.
377-
let overlay_item = overlay
378-
.value_iter(start, end)
379-
.filter(|(_, v)| v.as_option().is_some())
380-
.next();
389+
let overlay_items = overlay.value_iter(start, end);
390+
let mut overlay_deletions = vec![];
381391

382-
if let Some((key_path, overlay_leaf)) = overlay_item {
383-
let value_hash = match overlay_leaf {
384-
// PANIC: we filtered out all deletions above.
385-
ValueChange::Delete => panic!(),
392+
for (key_path, overlay_change) in overlay_items {
393+
let value_hash = match overlay_change {
394+
ValueChange::Delete => {
395+
// All deletes must be collected to filter out from the beatree iterator.
396+
overlay_deletions.push(key_path);
397+
continue;
398+
}
399+
// If an insertion is found within the overlay, it is expected to be
400+
// the item associated with the leaf that is being fetched.
386401
ValueChange::Insert(value) => H::hash_value(value),
387402
ValueChange::InsertOverflow(_, value_hash) => value_hash.clone(),
388403
};
@@ -397,6 +412,7 @@ impl RequestState {
397412
let beatree_iterator = read_transaction.iterator(start, end);
398413
let needed_leaves = beatree_iterator.needed_leaves();
399414
RequestState::FetchingLeaf {
415+
overlay_deletions,
400416
beatree_iterator,
401417
needed_leaves,
402418
}

nomt/tests/overlay.rs

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,3 +160,95 @@ fn overlay_uncommitted_not_on_disk() {
160160
assert_eq!(test.read([2; 32]), None);
161161
assert_eq!(test.read([3; 32]), None);
162162
}
163+
164+
#[test]
165+
fn overlay_deletions() {
166+
let test_db = || -> Test {
167+
let mut test = Test::new("overlay_deletions");
168+
// subtree at 0000000_0/1
169+
test.write([0; 32], Some(vec![1, 1]));
170+
test.write([1; 32], Some(vec![2, 2]));
171+
172+
// subtree at 001000_00/01/10
173+
test.write([32; 32], Some(vec![1, 1]));
174+
test.write([33; 32], Some(vec![2, 2]));
175+
test.write([34; 32], Some(vec![3, 3]));
176+
177+
// subtree at 100000_00/01/10/11
178+
test.write([128; 32], Some(vec![4, 4]));
179+
test.write([129; 32], Some(vec![5, 5]));
180+
test.write([130; 32], Some(vec![6, 6]));
181+
test.write([131; 32], Some(vec![7, 7]));
182+
183+
test.commit();
184+
test
185+
};
186+
187+
// Delete the first item for each subtree
188+
let mut test = test_db();
189+
190+
test.write([0; 32], None);
191+
test.write([32; 32], None);
192+
test.write([128; 32], None);
193+
let overlay_a = test.update().0;
194+
195+
test.start_overlay_session([&overlay_a]);
196+
assert_eq!(test.read([0; 32]), None);
197+
assert_eq!(test.read([1; 32]), Some(vec![2, 2]));
198+
199+
assert_eq!(test.read([32; 32]), None);
200+
assert_eq!(test.read([33; 32]), Some(vec![2, 2]));
201+
assert_eq!(test.read([34; 32]), Some(vec![3, 3]));
202+
203+
assert_eq!(test.read([128; 32]), None);
204+
assert_eq!(test.read([129; 32]), Some(vec![5, 5]));
205+
assert_eq!(test.read([130; 32]), Some(vec![6, 6]));
206+
assert_eq!(test.read([131; 32]), Some(vec![7, 7]));
207+
208+
let _overlay_b = test.update().0;
209+
210+
// Delete the second item for each subtree
211+
let mut test = test_db();
212+
213+
test.write([1; 32], None);
214+
test.write([33; 32], None);
215+
test.write([129; 32], None);
216+
let overlay_a = test.update().0;
217+
218+
test.start_overlay_session([&overlay_a]);
219+
assert_eq!(test.read([0; 32]), Some(vec![1, 1]));
220+
assert_eq!(test.read([1; 32]), None);
221+
222+
assert_eq!(test.read([32; 32]), Some(vec![1, 1]));
223+
assert_eq!(test.read([33; 32]), None);
224+
assert_eq!(test.read([34; 32]), Some(vec![3, 3]));
225+
226+
assert_eq!(test.read([128; 32]), Some(vec![4, 4]));
227+
assert_eq!(test.read([129; 32]), None);
228+
assert_eq!(test.read([130; 32]), Some(vec![6, 6]));
229+
assert_eq!(test.read([131; 32]), Some(vec![7, 7]));
230+
231+
let _overlay_b = test.update().0;
232+
233+
// Sequence of deletes
234+
let mut test = test_db();
235+
236+
test.write([32; 32], None);
237+
test.write([33; 32], None);
238+
test.write([128; 32], None);
239+
test.write([129; 32], None);
240+
test.write([131; 32], None);
241+
let overlay_a = test.update().0;
242+
243+
test.start_overlay_session([&overlay_a]);
244+
assert_eq!(test.read([32; 32]), None);
245+
assert_eq!(test.read([33; 32]), None);
246+
assert_eq!(test.read([34; 32]), Some(vec![3, 3]));
247+
248+
assert_eq!(test.read([128; 32]), None);
249+
assert_eq!(test.read([129; 32]), None);
250+
assert_eq!(test.read([130; 32]), Some(vec![6, 6]));
251+
assert_eq!(test.read([131; 32]), None);
252+
253+
let _overlay_b = test.update().0;
254+
}

0 commit comments

Comments
 (0)