[thin_restore (rust)] Apply several fixes

- Fix reading queued blocks
- Fix unnecessary block shadowing when there's no remaining values
- Prevent superblock from overwritten
- Flush queued writes before updating superblock
This commit is contained in:
Ming-Hung Tsai 2021-05-02 23:51:56 +08:00
parent e9899ac610
commit 4b4584c830
3 changed files with 24 additions and 9 deletions

View File

@ -152,7 +152,7 @@ pub trait NodeIO<V: Unpack + Pack> {
fn write(&self, w: &mut WriteBatcher, keys: Vec<u64>, values: Vec<V>) -> Result<WriteResult>; fn write(&self, w: &mut WriteBatcher, keys: Vec<u64>, values: Vec<V>) -> Result<WriteResult>;
fn read( fn read(
&self, &self,
engine: &Arc<dyn IoEngine + Send + Sync>, w: &mut WriteBatcher,
block: u64, block: u64,
) -> Result<(Vec<u64>, Vec<V>)>; ) -> Result<(Vec<u64>, Vec<V>)>;
} }
@ -180,10 +180,10 @@ impl<V: Unpack + Pack> NodeIO<V> for LeafIO {
fn read( fn read(
&self, &self,
engine: &Arc<dyn IoEngine + Send + Sync>, w: &mut WriteBatcher,
block: u64, block: u64,
) -> Result<(Vec<u64>, Vec<V>)> { ) -> Result<(Vec<u64>, Vec<V>)> {
let b = engine.read(block)?; let b = w.read(block)?;
let path = Vec::new(); let path = Vec::new();
match unpack_node::<V>(&path, b.get_data(), true, true)? { match unpack_node::<V>(&path, b.get_data(), true, true)? {
Node::Internal { .. } => { Node::Internal { .. } => {
@ -217,10 +217,10 @@ impl NodeIO<u64> for InternalIO {
fn read( fn read(
&self, &self,
engine: &Arc<dyn IoEngine + Send + Sync>, w: &mut WriteBatcher,
block: u64, block: u64,
) -> Result<(Vec<u64>, Vec<u64>)> { ) -> Result<(Vec<u64>, Vec<u64>)> {
let b = engine.read(block)?; let b = w.read(block)?;
let path = Vec::new(); let path = Vec::new();
match unpack_node::<u64>(&path, b.get_data(), true, true)? { match unpack_node::<u64>(&path, b.get_data(), true, true)? {
Node::Internal { keys, values, .. } => Ok((keys, values)), Node::Internal { keys, values, .. } => Ok((keys, values)),
@ -307,7 +307,7 @@ impl<'a, V: Pack + Unpack + Clone> NodeBuilder<V> {
} }
// Decide if we're going to use the pre-built nodes. // Decide if we're going to use the pre-built nodes.
if self.values.len() < half_full { if (self.values.len() > 0) && (self.values.len() < half_full) {
// To avoid writing an under populated node we have to grab some // To avoid writing an under populated node we have to grab some
// values from the first of the shared nodes. // values from the first of the shared nodes.
let (keys, values) = self.read_node(w, nodes.get(0).unwrap().block)?; let (keys, values) = self.read_node(w, nodes.get(0).unwrap().block)?;
@ -345,7 +345,7 @@ impl<'a, V: Pack + Unpack + Clone> NodeBuilder<V> {
pub fn complete(mut self, w: &mut WriteBatcher) -> Result<Vec<NodeSummary>> { pub fn complete(mut self, w: &mut WriteBatcher) -> Result<Vec<NodeSummary>> {
let half_full = self.max_entries_per_node / 2; let half_full = self.max_entries_per_node / 2;
if (self.nodes.len() > 0) && (self.values.len() < half_full) { if (self.values.len() > 0) && (self.values.len() < half_full) && (self.nodes.len() > 0) {
// We don't have enough values to emit a node. So we're going to // We don't have enough values to emit a node. So we're going to
// have to rebalance with the previous node. // have to rebalance with the previous node.
self.unshift_node(w)?; self.unshift_node(w)?;
@ -364,8 +364,8 @@ impl<'a, V: Pack + Unpack + Clone> NodeBuilder<V> {
// We're only interested in the keys and values from the node, and // We're only interested in the keys and values from the node, and
// not whether it's a leaf or internal node. // not whether it's a leaf or internal node.
fn read_node(&self, w: &WriteBatcher, block: u64) -> Result<(Vec<u64>, Vec<V>)> { fn read_node(&self, w: &mut WriteBatcher, block: u64) -> Result<(Vec<u64>, Vec<V>)> {
self.nio.read(&w.engine, block) self.nio.read(w, block)
} }
/// Writes a node with the first 'nr_entries' values. /// Writes a node with the first 'nr_entries' values.

View File

@ -98,6 +98,7 @@ impl<'a> Pass1<'a> {
impl<'a> MetadataVisitor for Pass1<'a> { impl<'a> MetadataVisitor for Pass1<'a> {
fn superblock_b(&mut self, sb: &xml::Superblock) -> Result<Visit> { fn superblock_b(&mut self, sb: &xml::Superblock) -> Result<Visit> {
self.result.sb = Some(sb.clone()); self.result.sb = Some(sb.clone());
self.w.alloc()?;
Ok(Visit::Continue) Ok(Visit::Continue)
} }
@ -277,6 +278,8 @@ pub fn restore(opts: ThinRestoreOptions) -> Result<()> {
// FIXME: I think we need to decrement the shared leaves // FIXME: I think we need to decrement the shared leaves
// Build metadata space map // Build metadata space map
w.flush()?;
// Write the superblock // Write the superblock
if let Some(xml_sb) = pass.sb { if let Some(xml_sb) = pass.sb {
let sb = superblock::Superblock { let sb = superblock::Superblock {

View File

@ -65,6 +65,18 @@ impl WriteBatcher {
Ok(()) Ok(())
} }
pub fn read(&mut self, blocknr: u64) -> Result<Block> {
for b in self.queue.iter().rev() {
if b.loc == blocknr {
let r = Block::new(b.loc);
r.get_data().copy_from_slice(b.get_data());
return Ok(r);
}
}
self.engine.read(blocknr).map_err(|_| anyhow!("read block error"))
}
pub fn flush_(&mut self, queue: Vec<Block>) -> Result<()> { pub fn flush_(&mut self, queue: Vec<Block>) -> Result<()> {
self.engine.write_many(&queue)?; self.engine.write_many(&queue)?;
Ok(()) Ok(())