Skip to content

Commit 9151587

Browse files
committed
fix: properly handle deletions within overlays
1 parent 543ed55 commit 9151587

File tree

2 files changed

+116
-15
lines changed

2 files changed

+116
-15
lines changed

nomt/src/merkle/seek.rs

Lines changed: 24 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,17 @@ 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 (key, value_hash) = loop {
208+
match beatree_iterator.next() {
209+
None => panic!("leaf must exist position={}", self.position.path()),
210+
Some(IterOutput::Blocked) => return,
211+
Some(IterOutput::Item(key, _value)) if overlay_deletions.first() == Some(&key) => {
212+
overlay_deletions.remove(0);
213+
continue;
214+
}
215+
Some(IterOutput::Item(key, value)) => break (key, H::hash_value(&value)),
216+
Some(IterOutput::OverflowItem(key, value_hash, _)) => break (key, value_hash),
211217
}
212-
Some(IterOutput::OverflowItem(key, value_hash, _)) => (key, value_hash),
213218
};
214219

215220
self.state = RequestState::Completed(Some(trie::LeafData {
@@ -351,6 +356,7 @@ enum RequestState {
351356
Seeking,
352357
// Fetching one leaf
353358
FetchingLeaf {
359+
overlay_deletions: Vec<KeyPath>,
354360
beatree_iterator: BeatreeIterator,
355361
needed_leaves: NeededLeavesIter,
356362
},
@@ -373,16 +379,18 @@ impl RequestState {
373379
) -> Self {
374380
let (start, end) = range_bounds(pos.raw_path(), pos.depth() as usize);
375381

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();
382+
let overlay_items = overlay.value_iter(start, end);
383+
let mut overlay_deletions = vec![];
381384

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!(),
385+
for (key_path, overlay_change) in overlay_items {
386+
let value_hash = match overlay_change {
387+
ValueChange::Delete => {
388+
// All deletes must be collected to filter out from the beatree iterator.
389+
overlay_deletions.push(key_path);
390+
continue;
391+
}
392+
// If an insertion is found within the overlay, it is expected to be
393+
// the item associated with the leaf that is being fetched.
386394
ValueChange::Insert(value) => H::hash_value(value),
387395
ValueChange::InsertOverflow(_, value_hash) => value_hash.clone(),
388396
};
@@ -397,6 +405,7 @@ impl RequestState {
397405
let beatree_iterator = read_transaction.iterator(start, end);
398406
let needed_leaves = beatree_iterator.needed_leaves();
399407
RequestState::FetchingLeaf {
408+
overlay_deletions,
400409
beatree_iterator,
401410
needed_leaves,
402411
}

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)