Fix for buffer-pruned positions in MMR store

The MMR storage has a buffer for all changes so they can either
be discarded without side effects or committed to disk. Pruning
can also happen in the buffer if an input directly spends an
output in a block (not likely), or a fork has an input spending
a previous output within it.

When the buffer gets flushed to storage, the pruned element was
just skipped, causing an offset within the underlying storage and
a shorter file than expected. This fix writes zeroes instead, so
the size is consistent. Note that the zeroes will be removed with
all other pruned elements on next compaction.

Fixes #444
This commit is contained in:
Ignotus Peverell 2017-12-09 18:43:13 +00:00
parent 001fd3789c
commit 6ba22e71c8
No known key found for this signature in database
GPG key ID: 99CD25F39F8F8211

View file

@ -394,18 +394,25 @@ where
/// data has been successfully written to disk. /// data has been successfully written to disk.
pub fn sync(&mut self) -> io::Result<()> { pub fn sync(&mut self) -> io::Result<()> {
// truncating the storage file if a rewind occurred // truncating the storage file if a rewind occurred
let record_len = 32 + T::sum_len() as u64;
if let Some((pos, _, _)) = self.rewind { if let Some((pos, _, _)) = self.rewind {
let record_len = 32 + T::sum_len() as u64;
self.hashsum_file.truncate(pos * record_len)?; self.hashsum_file.truncate(pos * record_len)?;
} }
for elem in &self.buffer.elems { for elem in &self.buffer.elems {
if let Some(ref hs) = *elem { let res = if let Some(ref hs) = *elem {
if let Err(e) = self.hashsum_file.append(&ser::ser_vec(&hs).unwrap()[..]) { self.hashsum_file.append(&ser::ser_vec(&hs).unwrap()[..])
return Err(io::Error::new( } else {
io::ErrorKind::Interrupted, // the element has alredy been pruned in the buffer, we just insert
format!("Could not write to log storage, disk full? {:?}", e), // zeros until compaction to avoid wrong hashum store offsets
)); self.hashsum_file.append(&vec![0; record_len as usize])
} };
if let Err(e) = res {
return Err(io::Error::new(
io::ErrorKind::Interrupted,
format!("Could not write to log storage, disk full? {:?}", e),
));
} }
} }
@ -422,7 +429,7 @@ where
if let Some((_, _, bi)) = self.rewind { if let Some((_, _, bi)) = self.rewind {
self.buffer_index = bi; self.buffer_index = bi;
} }
self.buffer = VecBackend::new(); self.buffer.clear();
self.remove_log.discard(); self.remove_log.discard();
self.rewind = None; self.rewind = None;
} }