Skip to content

Commit d2ab544

Browse files
committed
fix: flush_all removes blocks from the BufferedBlockstore
* add tests
1 parent 9a3295e commit d2ab544

File tree

1 file changed

+105
-4
lines changed

1 file changed

+105
-4
lines changed

fvm/src/blockstore/buffered.rs

Lines changed: 105 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,18 @@ where
4040
/// Unlike the standard flush() operation which only writes blocks connected
4141
/// to the final state tree, this writes every block created during execution.
4242
pub fn flush_all(&self) -> Result<()> {
43-
log::info!(
43+
log::debug!(
4444
"Flushing all ({}) cache blocks to blockstore",
45-
self.write.borrow().len()
45+
self.buffer_len()
4646
);
47-
self.base
48-
.put_many_keyed(self.write.borrow().iter().map(|(k, v)| (*k, v.as_slice())))
47+
48+
self.base.put_many_keyed(self.write.borrow_mut().drain())?;
49+
50+
Ok(())
51+
}
52+
53+
pub fn buffer_len(&self) -> usize {
54+
self.write.borrow().len()
4955
}
5056
}
5157

@@ -342,4 +348,99 @@ mod tests {
342348
assert_eq!(buf_store.get(&sealed_comm_cid).unwrap(), None);
343349
assert_eq!(mem.get_cbor::<u8>(&unconnected).unwrap(), None);
344350
}
351+
352+
#[test]
353+
fn test_flush_vs_flush_all() {
354+
fn setup(
355+
mem: &MemoryBlockstore,
356+
buf_store: &BufferedBlockstore<&MemoryBlockstore>,
357+
) -> (Cid, Cid, Cid, Cid) {
358+
// A DAG of 2 blocks
359+
let value1 = 42u8;
360+
let value2 = 84u8;
361+
let value1_cid = buf_store.put_cbor(&value1, Code::Blake2b256).unwrap();
362+
let root_cid = buf_store
363+
.put_cbor(&(value1_cid, value2), Code::Blake2b256)
364+
.unwrap();
365+
366+
// Two additional disconnected blocks
367+
let disconnected1 = 100u8;
368+
let disconnected2 = 200u8;
369+
let disconnected1_cid = buf_store
370+
.put_cbor(&disconnected1, Code::Blake2b256)
371+
.unwrap();
372+
let disconnected2_cid = buf_store
373+
.put_cbor(&disconnected2, Code::Blake2b256)
374+
.unwrap();
375+
376+
// Verify initial state - everything in buffer, nothing in backing store
377+
assert_eq!(buf_store.get_cbor::<u8>(&value1_cid).unwrap(), Some(value1));
378+
assert_eq!(
379+
buf_store.get_cbor::<(Cid, u8)>(&root_cid).unwrap(),
380+
Some((value1_cid, value2))
381+
);
382+
assert_eq!(
383+
buf_store.get_cbor::<u8>(&disconnected1_cid).unwrap(),
384+
Some(disconnected1)
385+
);
386+
assert_eq!(
387+
buf_store.get_cbor::<u8>(&disconnected2_cid).unwrap(),
388+
Some(disconnected2)
389+
);
390+
assert_eq!(mem.get_cbor::<u8>(&value1_cid).unwrap(), None);
391+
assert_eq!(mem.get_cbor::<(Cid, u8)>(&root_cid).unwrap(), None);
392+
assert_eq!(mem.get_cbor::<u8>(&disconnected1_cid).unwrap(), None);
393+
assert_eq!(mem.get_cbor::<u8>(&disconnected2_cid).unwrap(), None);
394+
395+
(root_cid, value1_cid, disconnected1_cid, disconnected2_cid)
396+
}
397+
398+
// Case 1: flush operation only writes connected blocks
399+
{
400+
let mem = MemoryBlockstore::default();
401+
let buf_store = BufferedBlockstore::new(&mem);
402+
let (root_cid, value1_cid, disconnected1_cid, disconnected2_cid) =
403+
setup(&mem, &buf_store);
404+
405+
// flush() should write only he DAG
406+
buf_store.flush(&root_cid).unwrap();
407+
408+
// DAG should be in backing store
409+
assert_eq!(mem.get_cbor::<u8>(&value1_cid).unwrap(), Some(42u8));
410+
assert_eq!(
411+
mem.get_cbor::<(Cid, u8)>(&root_cid).unwrap(),
412+
Some((value1_cid, 84u8))
413+
);
414+
415+
// Disconnected blocks should NOT be in backing store
416+
assert_eq!(mem.get_cbor::<u8>(&disconnected1_cid).unwrap(), None);
417+
assert_eq!(mem.get_cbor::<u8>(&disconnected2_cid).unwrap(), None);
418+
419+
// Verify that the buffer still contains the disconnected blocks
420+
assert_eq!(buf_store.buffer_len(), 2);
421+
}
422+
423+
// Case 2: flush_all operation writes all blocks
424+
{
425+
let mem = MemoryBlockstore::default();
426+
let buf_store = BufferedBlockstore::new(&mem);
427+
let (root_cid, value1_cid, disconnected1_cid, disconnected2_cid) =
428+
setup(&mem, &buf_store);
429+
430+
// flush_all() should write all blocks
431+
buf_store.flush_all().unwrap();
432+
433+
// All blocks should be in backing store
434+
assert_eq!(mem.get_cbor::<u8>(&value1_cid).unwrap(), Some(42u8));
435+
assert_eq!(
436+
mem.get_cbor::<(Cid, u8)>(&root_cid).unwrap(),
437+
Some((value1_cid, 84u8))
438+
);
439+
assert_eq!(mem.get_cbor::<u8>(&disconnected1_cid).unwrap(), Some(100u8));
440+
assert_eq!(mem.get_cbor::<u8>(&disconnected2_cid).unwrap(), Some(200u8));
441+
442+
// Verify that all blocks are removed from the buffer
443+
assert_eq!(buf_store.buffer_len(), 0);
444+
}
445+
}
345446
}

0 commit comments

Comments
 (0)