mirror of
https://github.com/mimblewimble/grin.git
synced 2025-02-01 17:01:09 +03:00
86c1d7683b
* header MMR in use within txhashset itself works with fast sync not yet in place for initial header sync * add the (currently unused) sync_head mmr * use sync MMR during fast sync rebuild header MMR after we validate full txhashset after download * support missing header MMR (rebuild as necessary) for legacy nodes * rename to HashOnly * cleanup backend.append() * simplify vec_backend to match simpler append api
148 lines
4.4 KiB
Rust
148 lines
4.4 KiB
Rust
// Copyright 2018 The Grin Developers
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
//! The deprecated rm_log impl. Still used for migration
|
|
//! from rm_log -> leaf_set on startup and fast sync.
|
|
|
|
use std::fs::File;
|
|
use std::io::{self, BufWriter, Write};
|
|
|
|
use core::ser;
|
|
use types::read_ordered_vec;
|
|
|
|
/// Log file fully cached in memory containing all positions that should be
|
|
/// eventually removed from the MMR append-only data file. Allows quick
|
|
/// checking of whether a piece of data has been marked for deletion. When the
|
|
/// log becomes too long, the MMR backend will actually remove chunks from the
|
|
/// MMR data file and truncate the remove log.
|
|
pub struct RemoveLog {
|
|
path: String,
|
|
/// Ordered vector of MMR positions that should get eventually removed.
|
|
pub removed: Vec<(u64, u32)>,
|
|
// Holds positions temporarily until flush is called.
|
|
removed_tmp: Vec<(u64, u32)>,
|
|
// Holds truncated removed temporarily until discarded or committed
|
|
removed_bak: Vec<(u64, u32)>,
|
|
}
|
|
|
|
impl RemoveLog {
|
|
/// Open the remove log file.
|
|
/// The content of the file will be read in memory for fast checking.
|
|
pub fn open(path: String) -> io::Result<RemoveLog> {
|
|
let removed = read_ordered_vec(path.clone(), 12)?;
|
|
Ok(RemoveLog {
|
|
path: path,
|
|
removed: removed,
|
|
removed_tmp: vec![],
|
|
removed_bak: vec![],
|
|
})
|
|
}
|
|
|
|
/// Rewinds the remove log back to the provided index.
|
|
/// We keep everything in the rm_log from that index and earlier.
|
|
/// In practice the index is a block height, so we rewind back to that block
|
|
/// keeping everything in the rm_log up to and including that block.
|
|
pub fn rewind(&mut self, idx: u32) -> io::Result<()> {
|
|
// backing it up before truncating (unless we already have a backup)
|
|
if self.removed_bak.is_empty() {
|
|
self.removed_bak = self.removed.clone();
|
|
}
|
|
|
|
if idx == 0 {
|
|
self.removed = vec![];
|
|
self.removed_tmp = vec![];
|
|
} else {
|
|
// retain rm_log entries up to and including those at the provided index
|
|
self.removed.retain(|&(_, x)| x <= idx);
|
|
self.removed_tmp.retain(|&(_, x)| x <= idx);
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
/// Append a set of new positions to the remove log. Both adds those
|
|
/// positions the ordered in-memory set and to the file.
|
|
pub fn append(&mut self, elmts: Vec<u64>, index: u32) -> io::Result<()> {
|
|
for elmt in elmts {
|
|
match self.removed_tmp.binary_search(&(elmt, index)) {
|
|
Ok(_) => continue,
|
|
Err(idx) => {
|
|
self.removed_tmp.insert(idx, (elmt, index));
|
|
}
|
|
}
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
/// Flush the positions to remove to file.
|
|
pub fn flush(&mut self) -> io::Result<()> {
|
|
for elmt in &self.removed_tmp {
|
|
match self.removed.binary_search(&elmt) {
|
|
Ok(_) => continue,
|
|
Err(idx) => {
|
|
self.removed.insert(idx, *elmt);
|
|
}
|
|
}
|
|
}
|
|
let mut file = BufWriter::new(File::create(self.path.clone())?);
|
|
for elmt in &self.removed {
|
|
file.write_all(&ser::ser_vec(&elmt).unwrap()[..])?;
|
|
}
|
|
self.removed_tmp = vec![];
|
|
self.removed_bak = vec![];
|
|
file.flush()
|
|
}
|
|
|
|
/// Discard pending changes
|
|
pub fn discard(&mut self) {
|
|
if self.removed_bak.len() > 0 {
|
|
self.removed = self.removed_bak.clone();
|
|
self.removed_bak = vec![];
|
|
}
|
|
self.removed_tmp = vec![];
|
|
}
|
|
|
|
/// Whether the remove log currently includes the provided position.
|
|
pub fn includes(&self, elmt: u64) -> bool {
|
|
include_tuple(&self.removed, elmt) || include_tuple(&self.removed_tmp, elmt)
|
|
}
|
|
|
|
/// Number of positions stored in the remove log.
|
|
pub fn len(&self) -> usize {
|
|
self.removed.len()
|
|
}
|
|
|
|
/// Return vec of pos for removed elements before the provided cutoff index.
|
|
/// Useful for when we prune and compact an MMR.
|
|
pub fn removed_pre_cutoff(&self, cutoff_idx: u32) -> Vec<u64> {
|
|
self.removed
|
|
.iter()
|
|
.filter_map(
|
|
|&(pos, idx)| {
|
|
if idx < cutoff_idx {
|
|
Some(pos)
|
|
} else {
|
|
None
|
|
}
|
|
},
|
|
).collect()
|
|
}
|
|
}
|
|
|
|
fn include_tuple(v: &Vec<(u64, u32)>, e: u64) -> bool {
|
|
if let Err(pos) = v.binary_search(&(e, 0)) {
|
|
if pos < v.len() && v[pos].0 == e {
|
|
return true;
|
|
}
|
|
}
|
|
false
|
|
}
|