Merge branch 'main' into rust-cache-tools
This commit is contained in:
+3
-1
@@ -539,6 +539,7 @@ pub fn unpack_node<V: Unpack>(
|
||||
}
|
||||
|
||||
if !is_root {
|
||||
/*
|
||||
let min = header.max_entries / 3;
|
||||
if header.nr_entries < min {
|
||||
return Err(node_err_s(
|
||||
@@ -549,6 +550,7 @@ pub fn unpack_node<V: Unpack>(
|
||||
),
|
||||
));
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
@@ -558,7 +560,7 @@ pub fn unpack_node<V: Unpack>(
|
||||
for k in &keys {
|
||||
if let Some(l) = last {
|
||||
if k <= l {
|
||||
return Err(node_err(&path, "keys out of order"));
|
||||
return Err(node_err(&path, &format!("keys out of order: {} <= {}", k, l)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+377
-203
@@ -13,6 +13,70 @@ use crate::write_batcher::*;
|
||||
|
||||
//------------------------------------------
|
||||
|
||||
/// A little ref counter abstraction. Used to manage counts for btree
|
||||
/// values (eg, the block/time in a thin mapping tree).
|
||||
pub trait RefCounter<Value> {
|
||||
fn get(&self, v: &Value) -> Result<u32>;
|
||||
fn inc(&mut self, v: &Value) -> Result<()>;
|
||||
fn dec(&mut self, v: &Value) -> Result<()>;
|
||||
}
|
||||
|
||||
pub struct NoopRC {}
|
||||
|
||||
impl<Value> RefCounter<Value> for NoopRC {
|
||||
fn get(&self, _v: &Value) -> Result<u32> {
|
||||
Ok(0)
|
||||
}
|
||||
fn inc(&mut self, _v: &Value) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
fn dec(&mut self, _v: &Value) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Wraps a space map up to become a RefCounter.
|
||||
struct SMRefCounter {
|
||||
sm: Arc<Mutex<dyn SpaceMap>>,
|
||||
}
|
||||
|
||||
impl RefCounter<u64> for SMRefCounter {
|
||||
fn get(&self, v: &u64) -> Result<u32> {
|
||||
self.sm.lock().unwrap().get(*v)
|
||||
}
|
||||
|
||||
fn inc(&mut self, v: &u64) -> Result<()> {
|
||||
self.sm.lock().unwrap().inc(*v, 1)
|
||||
}
|
||||
|
||||
fn dec(&mut self, v: &u64) -> Result<()> {
|
||||
self.sm.lock().unwrap().dec(*v)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------
|
||||
|
||||
// Building a btree for a given set of values is straight forward.
|
||||
// But often we want to merge shared subtrees into the btree we're
|
||||
// building, which _is_ complicated. Requiring rebalancing of nodes,
|
||||
// and careful copy-on-write operations so we don't disturb the shared
|
||||
// subtree.
|
||||
//
|
||||
// To avoid these problems this code never produces shared internal nodes.
|
||||
// With the large fan out of btrees this isn't really a problem; we'll
|
||||
// allocate more nodes than optimum, but not many compared to the number
|
||||
// of leaves. Also we can pack the leaves much better than the kernel
|
||||
// does due to out of order insertions.
|
||||
//
|
||||
// There are thus two stages to building a btree.
|
||||
//
|
||||
// i) Produce a list of populated leaves. These leaves may well be shared.
|
||||
// ii) Build the upper levels of the btree above the leaves.
|
||||
|
||||
//------------------------------------------
|
||||
|
||||
/// Pack the given node ready to write to disk.
|
||||
pub fn pack_node<W: WriteBytesExt, V: Pack + Unpack>(node: &Node<V>, w: &mut W) -> Result<()> {
|
||||
match node {
|
||||
Node::Internal {
|
||||
@@ -62,256 +126,366 @@ pub fn pack_node<W: WriteBytesExt, V: Pack + Unpack>(node: &Node<V>, w: &mut W)
|
||||
|
||||
pub fn calc_max_entries<V: Unpack>() -> usize {
|
||||
let elt_size = 8 + V::disk_size() as usize;
|
||||
((BLOCK_SIZE - NodeHeader::disk_size() as usize) / elt_size) as usize
|
||||
let total = ((BLOCK_SIZE - NodeHeader::disk_size() as usize) / elt_size) as usize;
|
||||
total / 3 * 3
|
||||
}
|
||||
|
||||
//------------------------------------------
|
||||
|
||||
struct Entries<V> {
|
||||
pub max_entries: usize,
|
||||
entries: VecDeque<(u64, V)>,
|
||||
pub struct WriteResult {
|
||||
first_key: u64,
|
||||
loc: u64,
|
||||
}
|
||||
|
||||
enum Action<V> {
|
||||
EmitNode(Vec<u64>, Vec<V>), // keys, values
|
||||
}
|
||||
|
||||
use Action::*;
|
||||
|
||||
impl<V> Entries<V> {
|
||||
pub fn new(max_entries: usize) -> Entries<V> {
|
||||
Entries {
|
||||
max_entries,
|
||||
entries: VecDeque::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_entry(&mut self, k: u64, v: V) -> Vec<Action<V>> {
|
||||
let mut result = Vec::new();
|
||||
|
||||
if self.full() {
|
||||
let (keys, values) = self.pop(self.max_entries);
|
||||
result.push(EmitNode(keys, values));
|
||||
}
|
||||
|
||||
self.entries.push_back((k, v));
|
||||
result
|
||||
}
|
||||
|
||||
fn complete_(&mut self, result: &mut Vec<Action<V>>) {
|
||||
let n = self.entries.len();
|
||||
|
||||
if n >= self.max_entries {
|
||||
let n1 = n / 2;
|
||||
let n2 = n - n1;
|
||||
let (keys1, values1) = self.pop(n1);
|
||||
let (keys2, values2) = self.pop(n2);
|
||||
|
||||
result.push(EmitNode(keys1, values1));
|
||||
result.push(EmitNode(keys2, values2));
|
||||
} else if n > 0 {
|
||||
let (keys, values) = self.pop(n);
|
||||
result.push(EmitNode(keys, values));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn complete(&mut self) -> Vec<Action<V>> {
|
||||
let mut result = Vec::new();
|
||||
self.complete_(&mut result);
|
||||
result
|
||||
}
|
||||
|
||||
fn full(&self) -> bool {
|
||||
self.entries.len() >= 2 * self.max_entries
|
||||
}
|
||||
|
||||
fn pop(&mut self, count: usize) -> (Vec<u64>, Vec<V>) {
|
||||
let mut keys = Vec::new();
|
||||
let mut values = Vec::new();
|
||||
|
||||
for _i in 0..count {
|
||||
let (k, v) = self.entries.pop_front().unwrap();
|
||||
keys.push(k);
|
||||
values.push(v);
|
||||
}
|
||||
|
||||
(keys, values)
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub struct NodeSummary {
|
||||
block: u64,
|
||||
nr_entries: usize,
|
||||
key_low: u64,
|
||||
key_high: u64, // inclusive
|
||||
}
|
||||
|
||||
//------------------------------------------
|
||||
|
||||
fn write_node_<V: Unpack + Pack>(w: &mut WriteBatcher, mut node: Node<V>) -> Result<(u64, u64)> {
|
||||
/// Write a node to a free metadata block.
|
||||
fn write_node_<V: Unpack + Pack>(w: &mut WriteBatcher, mut node: Node<V>) -> Result<WriteResult> {
|
||||
let keys = node.get_keys();
|
||||
let first_key = *keys.first().unwrap_or(&0u64);
|
||||
let first_key = keys.first().unwrap_or(&0u64).clone();
|
||||
|
||||
let loc = w.alloc()?;
|
||||
node.set_block(loc);
|
||||
let b = w.alloc()?;
|
||||
node.set_block(b.loc);
|
||||
|
||||
let b = Block::new(loc);
|
||||
let mut cursor = Cursor::new(b.get_data());
|
||||
pack_node(&node, &mut cursor)?;
|
||||
let loc = b.loc;
|
||||
w.write(b, checksum::BT::NODE)?;
|
||||
|
||||
Ok((first_key, loc))
|
||||
Ok(WriteResult { first_key, loc })
|
||||
}
|
||||
|
||||
fn write_leaf<V: Unpack + Pack>(
|
||||
w: &mut WriteBatcher,
|
||||
keys: Vec<u64>,
|
||||
values: Vec<V>,
|
||||
) -> Result<(u64, u64)> {
|
||||
let header = NodeHeader {
|
||||
block: 0,
|
||||
is_leaf: true,
|
||||
nr_entries: keys.len() as u32,
|
||||
max_entries: calc_max_entries::<V>() as u32,
|
||||
value_size: V::disk_size(),
|
||||
};
|
||||
|
||||
let node = Node::Leaf {
|
||||
header,
|
||||
keys,
|
||||
values,
|
||||
};
|
||||
|
||||
write_node_(w, node)
|
||||
/// A node writer takes a Vec of values and packs them into
|
||||
/// a btree node. It's up to the specific implementation to
|
||||
/// decide if it produces internal or leaf nodes.
|
||||
pub trait NodeIO<V: Unpack + Pack> {
|
||||
fn write(&self, w: &mut WriteBatcher, keys: Vec<u64>, values: Vec<V>) -> Result<WriteResult>;
|
||||
fn read(&self, w: &mut WriteBatcher, block: u64) -> Result<(Vec<u64>, Vec<V>)>;
|
||||
}
|
||||
|
||||
fn write_internal(w: &mut WriteBatcher, keys: Vec<u64>, values: Vec<u64>) -> Result<(u64, u64)> {
|
||||
let header = NodeHeader {
|
||||
block: 0,
|
||||
is_leaf: false,
|
||||
nr_entries: keys.len() as u32,
|
||||
max_entries: calc_max_entries::<u64>() as u32,
|
||||
value_size: u64::disk_size(),
|
||||
};
|
||||
pub struct LeafIO {}
|
||||
|
||||
let node: Node<u64> = Node::Internal {
|
||||
header,
|
||||
keys,
|
||||
values,
|
||||
};
|
||||
impl<V: Unpack + Pack> NodeIO<V> for LeafIO {
|
||||
fn write(&self, w: &mut WriteBatcher, keys: Vec<u64>, values: Vec<V>) -> Result<WriteResult> {
|
||||
let header = NodeHeader {
|
||||
block: 0,
|
||||
is_leaf: true,
|
||||
nr_entries: keys.len() as u32,
|
||||
max_entries: calc_max_entries::<V>() as u32,
|
||||
value_size: V::disk_size(),
|
||||
};
|
||||
|
||||
write_node_(w, node)
|
||||
}
|
||||
let node = Node::Leaf {
|
||||
header,
|
||||
keys,
|
||||
values,
|
||||
};
|
||||
|
||||
pub struct Builder<V: Unpack + Pack> {
|
||||
w: WriteBatcher,
|
||||
entries: Entries<V>,
|
||||
|
||||
max_internal_entries: usize,
|
||||
internal_entries: Vec<Entries<u64>>,
|
||||
|
||||
root: u64,
|
||||
}
|
||||
|
||||
impl<V: Unpack + Pack> Builder<V> {
|
||||
pub fn new(
|
||||
engine: Arc<dyn IoEngine + Send + Sync>,
|
||||
sm: Arc<Mutex<dyn SpaceMap>>,
|
||||
) -> Builder<V> {
|
||||
let max_entries = calc_max_entries::<V>();
|
||||
let max_internal_entries = calc_max_entries::<u64>();
|
||||
|
||||
Builder {
|
||||
w: WriteBatcher::new(engine, sm, 256),
|
||||
entries: Entries::new(max_entries),
|
||||
max_internal_entries,
|
||||
internal_entries: Vec::new(),
|
||||
root: 0,
|
||||
}
|
||||
write_node_(w, node)
|
||||
}
|
||||
|
||||
pub fn add_entry(&mut self, k: u64, v: V) -> Result<()> {
|
||||
let actions = self.entries.add_entry(k, v);
|
||||
for a in actions {
|
||||
self.perform_action(a)?;
|
||||
fn read(&self, w: &mut WriteBatcher, block: u64) -> Result<(Vec<u64>, Vec<V>)> {
|
||||
let b = w.read(block)?;
|
||||
let path = Vec::new();
|
||||
match unpack_node::<V>(&path, b.get_data(), true, true)? {
|
||||
Node::Internal { .. } => {
|
||||
panic!("unexpected internal node");
|
||||
}
|
||||
Node::Leaf { keys, values, .. } => Ok((keys, values)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct InternalIO {}
|
||||
|
||||
impl NodeIO<u64> for InternalIO {
|
||||
fn write(&self, w: &mut WriteBatcher, keys: Vec<u64>, values: Vec<u64>) -> Result<WriteResult> {
|
||||
let header = NodeHeader {
|
||||
block: 0,
|
||||
is_leaf: false,
|
||||
nr_entries: keys.len() as u32,
|
||||
max_entries: calc_max_entries::<u64>() as u32,
|
||||
value_size: u64::disk_size(),
|
||||
};
|
||||
|
||||
let node: Node<u64> = Node::Internal {
|
||||
header,
|
||||
keys,
|
||||
values,
|
||||
};
|
||||
|
||||
write_node_(w, node)
|
||||
}
|
||||
|
||||
fn read(&self, w: &mut WriteBatcher, block: u64) -> Result<(Vec<u64>, Vec<u64>)> {
|
||||
let b = w.read(block)?;
|
||||
let path = Vec::new();
|
||||
match unpack_node::<u64>(&path, b.get_data(), true, true)? {
|
||||
Node::Internal { keys, values, .. } => Ok((keys, values)),
|
||||
Node::Leaf { .. } => {
|
||||
panic!("unexpected leaf node");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------
|
||||
|
||||
/// This takes a sequence of values or nodes, and builds a vector of leaf nodes.
|
||||
/// Care is taken to make sure that all nodes are at least half full unless there's
|
||||
/// only a single node.
|
||||
pub struct NodeBuilder<V: Pack + Unpack> {
|
||||
nio: Box<dyn NodeIO<V>>,
|
||||
value_rc: Box<dyn RefCounter<V>>,
|
||||
max_entries_per_node: usize,
|
||||
values: VecDeque<(u64, V)>,
|
||||
nodes: Vec<NodeSummary>,
|
||||
}
|
||||
|
||||
/// When the builder is including pre-built nodes it has to decide whether
|
||||
/// to use the node as given, or read it and import the values directly
|
||||
/// for balancing reasons. This struct is used to stop us re-reading
|
||||
/// the NodeHeaders of nodes that are shared multiple times.
|
||||
#[derive(Clone)]
|
||||
pub struct NodeSummary {
|
||||
block: u64,
|
||||
key: u64,
|
||||
nr_entries: usize,
|
||||
|
||||
/// This node was passed in pre-built. Important for deciding if
|
||||
/// we need to adjust the ref counts if we unpack.
|
||||
shared: bool,
|
||||
}
|
||||
|
||||
impl<'a, V: Pack + Unpack + Clone> NodeBuilder<V> {
|
||||
/// Create a new NodeBuilder
|
||||
pub fn new(nio: Box<dyn NodeIO<V>>, value_rc: Box<dyn RefCounter<V>>) -> Self {
|
||||
NodeBuilder {
|
||||
nio,
|
||||
value_rc,
|
||||
max_entries_per_node: calc_max_entries::<V>(),
|
||||
values: VecDeque::new(),
|
||||
nodes: Vec::new(),
|
||||
}
|
||||
}
|
||||
/// Push a single value. This may emit a new node, hence the Result
|
||||
/// return type. The value's ref count will be incremented.
|
||||
pub fn push_value(&mut self, w: &mut WriteBatcher, key: u64, val: V) -> Result<()> {
|
||||
// Have we got enough values to emit a node? We try and keep
|
||||
// at least max_entries_per_node entries unflushed so we
|
||||
// can ensure the final node is balanced properly.
|
||||
if self.values.len() == self.max_entries_per_node * 2 {
|
||||
self.emit_node(w)?;
|
||||
}
|
||||
|
||||
self.value_rc.inc(&val)?;
|
||||
self.values.push_back((key, val));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn add_leaf_node(&mut self, leaf: &NodeSummary) -> Result<()> {
|
||||
match leaf.nr_entries {
|
||||
n if n == 0 => {
|
||||
// Do nothing
|
||||
},
|
||||
n if n < (self.entries.max_entries / 2) => {
|
||||
// FIXME: what if we've already queued a handful of entries for a node?
|
||||
// Add the entries individually
|
||||
todo!();
|
||||
},
|
||||
_n => {
|
||||
let actions = self.entries.complete();
|
||||
for a in actions {
|
||||
self.perform_action(a)?;
|
||||
}
|
||||
self.add_internal_entry(0, leaf.key_low, leaf.block)?;
|
||||
/// Push a number of prebuilt, shared nodes. The builder may decide to not
|
||||
/// use a shared node, instead reading the values and packing them
|
||||
/// directly. This may do IO to emit nodes, so returns a Result.
|
||||
/// Any shared nodes that are used have their block incremented in
|
||||
/// the space map. Will only increment the ref count for values
|
||||
/// contained in the nodes if it unpacks them.
|
||||
pub fn push_nodes(&mut self, w: &mut WriteBatcher, nodes: &Vec<NodeSummary>) -> Result<()> {
|
||||
assert!(nodes.len() > 0);
|
||||
|
||||
// As a sanity check we make sure that all the shared nodes contain the
|
||||
// minimum nr of entries.
|
||||
let half_full = self.max_entries_per_node / 2;
|
||||
for n in nodes {
|
||||
if n.nr_entries < half_full {
|
||||
panic!("under populated node");
|
||||
}
|
||||
}
|
||||
|
||||
// Decide if we're going to use the pre-built nodes.
|
||||
if (self.values.len() > 0) && (self.values.len() < half_full) {
|
||||
// To avoid writing an under populated node we have to grab some
|
||||
// values from the first of the shared nodes.
|
||||
let (keys, values) = self.read_node(w, nodes.get(0).unwrap().block)?;
|
||||
|
||||
for i in 0..keys.len() {
|
||||
self.value_rc.inc(&values[i])?;
|
||||
self.values.push_back((keys[i], values[i].clone()));
|
||||
}
|
||||
|
||||
// Flush all the values.
|
||||
self.emit_all(w)?;
|
||||
|
||||
// Add the remaining nodes.
|
||||
for i in 1..nodes.len() {
|
||||
let n = nodes.get(i).unwrap();
|
||||
w.sm.lock().unwrap().inc(n.block, 1)?;
|
||||
self.nodes.push(n.clone());
|
||||
}
|
||||
} else {
|
||||
// Flush all the values.
|
||||
self.emit_all(w)?;
|
||||
|
||||
// add the nodes
|
||||
for n in nodes {
|
||||
w.sm.lock().unwrap().inc(n.block, 1)?;
|
||||
self.nodes.push(n.clone());
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn complete(mut self) -> Result<u64> {
|
||||
let actions = self.entries.complete();
|
||||
for a in actions {
|
||||
self.perform_action(a)?;
|
||||
/// Signal that no more values or nodes will be pushed. Returns a
|
||||
/// vector of the built nodes. Consumes the builder.
|
||||
pub fn complete(mut self, w: &mut WriteBatcher) -> Result<Vec<NodeSummary>> {
|
||||
let half_full = self.max_entries_per_node / 2;
|
||||
|
||||
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
|
||||
// have to rebalance with the previous node.
|
||||
self.unshift_node(w)?;
|
||||
}
|
||||
self.w.flush()?;
|
||||
Ok(self.root)
|
||||
|
||||
self.emit_all(w)?;
|
||||
|
||||
if self.nodes.len() == 0 {
|
||||
self.emit_empty_leaf(w)?
|
||||
}
|
||||
|
||||
Ok(self.nodes)
|
||||
}
|
||||
|
||||
//--------------------
|
||||
//-------------------------
|
||||
|
||||
fn add_internal_entry(&mut self, level: usize, k: u64, v: u64) -> Result<()> {
|
||||
if self.internal_entries.len() == level {
|
||||
self.internal_entries
|
||||
.push(Entries::new(self.max_internal_entries));
|
||||
// We're only interested in the keys and values from the node, and
|
||||
// not whether it's a leaf or internal node.
|
||||
fn read_node(&self, w: &mut WriteBatcher, block: u64) -> Result<(Vec<u64>, Vec<V>)> {
|
||||
self.nio.read(w, block)
|
||||
}
|
||||
|
||||
/// Writes a node with the first 'nr_entries' values.
|
||||
fn emit_values(&mut self, w: &mut WriteBatcher, nr_entries: usize) -> Result<()> {
|
||||
assert!(nr_entries <= self.values.len());
|
||||
|
||||
// Write the node
|
||||
let mut keys = Vec::new();
|
||||
let mut values = Vec::new();
|
||||
|
||||
for _i in 0..nr_entries {
|
||||
let (k, v) = self.values.pop_front().unwrap();
|
||||
keys.push(k);
|
||||
values.push(v);
|
||||
}
|
||||
|
||||
let actions = self.internal_entries[level].add_entry(k, v);
|
||||
|
||||
for a in actions {
|
||||
self.perform_internal_action(level, a)?;
|
||||
}
|
||||
let wresult = self.nio.write(w, keys, values)?;
|
||||
|
||||
// Push a summary to the 'nodes' vector.
|
||||
self.nodes.push(NodeSummary {
|
||||
block: wresult.loc,
|
||||
key: wresult.first_key,
|
||||
nr_entries,
|
||||
shared: false,
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn perform_internal_action(&mut self, level: usize, action: Action<u64>) -> Result<()> {
|
||||
match action {
|
||||
EmitNode(keys, values) => {
|
||||
let (k, loc) = write_internal(&mut self.w, keys, values)?;
|
||||
self.add_internal_entry(level + 1, k, loc)?;
|
||||
self.root = loc;
|
||||
},
|
||||
}
|
||||
|
||||
Ok(())
|
||||
/// Writes a full node.
|
||||
fn emit_node(&mut self, w: &mut WriteBatcher) -> Result<()> {
|
||||
self.emit_values(w, self.max_entries_per_node)
|
||||
}
|
||||
|
||||
fn perform_action<V2: Unpack + Pack>(&mut self, action: Action<V2>) -> Result<()> {
|
||||
match action {
|
||||
EmitNode(keys, values) => {
|
||||
let (k, loc) = write_leaf(&mut self.w, keys, values)?;
|
||||
self.add_internal_entry(0, k, loc)?;
|
||||
},
|
||||
/// Emits all remaining values. Panics if there are more than 2 *
|
||||
/// max_entries_per_node values.
|
||||
fn emit_all(&mut self, w: &mut WriteBatcher) -> Result<()> {
|
||||
match self.values.len() {
|
||||
0 => {
|
||||
// There's nothing to emit
|
||||
Ok(())
|
||||
}
|
||||
n if n <= self.max_entries_per_node => {
|
||||
// Emit a single node.
|
||||
self.emit_values(w, n)
|
||||
}
|
||||
n if n <= self.max_entries_per_node * 2 => {
|
||||
// Emit two nodes.
|
||||
let n1 = n / 2;
|
||||
let n2 = n - n1;
|
||||
self.emit_values(w, n1)?;
|
||||
self.emit_values(w, n2)
|
||||
}
|
||||
_ => {
|
||||
panic!("self.values shouldn't have more than 2 * max_entries_per_node entries");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn emit_empty_leaf(&mut self, w: &mut WriteBatcher) -> Result<()> {
|
||||
self.emit_values(w, 0)
|
||||
}
|
||||
|
||||
/// Pops the last node, and prepends it's values to 'self.values'. Used
|
||||
/// to rebalance when we have insufficient values for a final node. The
|
||||
/// node is decremented in the space map.
|
||||
fn unshift_node(&mut self, w: &mut WriteBatcher) -> Result<()> {
|
||||
let ls = self.nodes.pop().unwrap();
|
||||
let (keys, values) = self.read_node(w, ls.block)?;
|
||||
w.sm.lock().unwrap().dec(ls.block)?;
|
||||
|
||||
let mut vals = VecDeque::new();
|
||||
|
||||
for i in 0..keys.len() {
|
||||
// We only need to inc the values if the node was pre built.
|
||||
if ls.shared {
|
||||
self.value_rc.inc(&values[i])?;
|
||||
}
|
||||
vals.push_back((keys[i], values[i].clone()));
|
||||
}
|
||||
|
||||
vals.append(&mut self.values);
|
||||
std::mem::swap(&mut self.values, &mut vals);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------
|
||||
|
||||
pub struct Builder<V: Unpack + Pack> {
|
||||
leaf_builder: NodeBuilder<V>,
|
||||
}
|
||||
|
||||
impl<V: Unpack + Pack + Clone> Builder<V> {
|
||||
pub fn new(value_rc: Box<dyn RefCounter<V>>) -> Builder<V> {
|
||||
Builder {
|
||||
leaf_builder: NodeBuilder::new(Box::new(LeafIO {}), value_rc),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn push_value(&mut self, w: &mut WriteBatcher, k: u64, v: V) -> Result<()> {
|
||||
self.leaf_builder.push_value(w, k, v)
|
||||
}
|
||||
|
||||
pub fn push_leaves(&mut self, w: &mut WriteBatcher, leaves: &Vec<NodeSummary>) -> Result<()> {
|
||||
self.leaf_builder.push_nodes(w, leaves)
|
||||
}
|
||||
|
||||
pub fn complete(self, w: &mut WriteBatcher) -> Result<u64> {
|
||||
let mut nodes = self.leaf_builder.complete(w)?;
|
||||
|
||||
// Now we iterate, adding layers of internal nodes until we end
|
||||
// up with a single root.
|
||||
while nodes.len() > 1 {
|
||||
let mut builder = NodeBuilder::new(
|
||||
Box::new(InternalIO {}),
|
||||
Box::new(SMRefCounter { sm: w.sm.clone() }),
|
||||
);
|
||||
|
||||
for n in nodes {
|
||||
builder.push_value(w, n.key, n.block)?;
|
||||
}
|
||||
|
||||
nodes = builder.complete(w)?;
|
||||
}
|
||||
|
||||
assert!(nodes.len() == 1);
|
||||
Ok(nodes[0].block)
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------
|
||||
|
||||
+2
-2
@@ -3,10 +3,10 @@ pub mod array_walker;
|
||||
pub mod bitset;
|
||||
pub mod btree;
|
||||
pub mod btree_builder;
|
||||
pub mod btree_merge;
|
||||
pub mod btree_leaf_walker;
|
||||
pub mod btree_merge;
|
||||
pub mod btree_walker;
|
||||
pub mod space_map;
|
||||
pub mod space_map_checker;
|
||||
pub mod space_map_disk;
|
||||
pub mod unpack;
|
||||
|
||||
|
||||
+14
-221
@@ -1,223 +1,7 @@
|
||||
use anyhow::{anyhow, Result};
|
||||
use byteorder::{LittleEndian, WriteBytesExt};
|
||||
use anyhow::Result;
|
||||
use fixedbitset::FixedBitSet;
|
||||
use nom::{multi::count, number::complete::*, IResult};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::boxed::Box;
|
||||
|
||||
use crate::io_engine::*;
|
||||
use crate::pdata::unpack::{Pack, Unpack};
|
||||
|
||||
//------------------------------------------
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SMRoot {
|
||||
pub nr_blocks: u64,
|
||||
pub nr_allocated: u64,
|
||||
pub bitmap_root: u64,
|
||||
pub ref_count_root: u64,
|
||||
}
|
||||
|
||||
pub fn unpack_root(data: &[u8]) -> Result<SMRoot> {
|
||||
match SMRoot::unpack(data) {
|
||||
Err(_e) => Err(anyhow!("couldn't parse SMRoot")),
|
||||
Ok((_i, v)) => Ok(v),
|
||||
}
|
||||
}
|
||||
|
||||
impl Unpack for SMRoot {
|
||||
fn disk_size() -> u32 {
|
||||
32
|
||||
}
|
||||
|
||||
fn unpack(data: &[u8]) -> IResult<&[u8], SMRoot> {
|
||||
let (i, nr_blocks) = le_u64(data)?;
|
||||
let (i, nr_allocated) = le_u64(i)?;
|
||||
let (i, bitmap_root) = le_u64(i)?;
|
||||
let (i, ref_count_root) = le_u64(i)?;
|
||||
|
||||
Ok((
|
||||
i,
|
||||
SMRoot {
|
||||
nr_blocks,
|
||||
nr_allocated,
|
||||
bitmap_root,
|
||||
ref_count_root,
|
||||
},
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct IndexEntry {
|
||||
pub blocknr: u64,
|
||||
pub nr_free: u32,
|
||||
pub none_free_before: u32,
|
||||
}
|
||||
|
||||
impl Unpack for IndexEntry {
|
||||
fn disk_size() -> u32 {
|
||||
16
|
||||
}
|
||||
|
||||
fn unpack(data: &[u8]) -> IResult<&[u8], Self> {
|
||||
let (i, blocknr) = le_u64(data)?;
|
||||
let (i, nr_free) = le_u32(i)?;
|
||||
let (i, none_free_before) = le_u32(i)?;
|
||||
|
||||
Ok((
|
||||
i,
|
||||
IndexEntry {
|
||||
blocknr,
|
||||
nr_free,
|
||||
none_free_before,
|
||||
},
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------
|
||||
|
||||
pub const MAX_METADATA_BITMAPS: usize = 255;
|
||||
|
||||
pub struct MetadataIndex {
|
||||
pub indexes: Vec<IndexEntry>,
|
||||
}
|
||||
|
||||
impl Unpack for MetadataIndex {
|
||||
fn disk_size() -> u32 {
|
||||
BLOCK_SIZE as u32
|
||||
}
|
||||
|
||||
fn unpack(data: &[u8]) -> IResult<&[u8], Self> {
|
||||
let (i, _csum) = le_u32(data)?;
|
||||
let (i, _padding) = le_u32(i)?;
|
||||
let (i, _blocknr) = le_u64(i)?;
|
||||
let (i, indexes) = count(IndexEntry::unpack, MAX_METADATA_BITMAPS)(i)?;
|
||||
|
||||
Ok((i, MetadataIndex { indexes }))
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct BitmapHeader {
|
||||
pub csum: u32,
|
||||
pub not_used: u32,
|
||||
pub blocknr: u64,
|
||||
}
|
||||
|
||||
impl Unpack for BitmapHeader {
|
||||
fn disk_size() -> u32 {
|
||||
16
|
||||
}
|
||||
|
||||
fn unpack(data: &[u8]) -> IResult<&[u8], Self> {
|
||||
let (i, csum) = le_u32(data)?;
|
||||
let (i, not_used) = le_u32(i)?;
|
||||
let (i, blocknr) = le_u64(i)?;
|
||||
|
||||
Ok((
|
||||
i,
|
||||
BitmapHeader {
|
||||
csum,
|
||||
not_used,
|
||||
blocknr,
|
||||
},
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl Pack for BitmapHeader {
|
||||
fn pack<W: WriteBytesExt>(&self, out: &mut W) -> Result<()> {
|
||||
out.write_u32::<LittleEndian>(self.csum)?;
|
||||
out.write_u32::<LittleEndian>(self.not_used)?;
|
||||
out.write_u64::<LittleEndian>(self.blocknr)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum BitmapEntry {
|
||||
Small(u8),
|
||||
Overflow,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Bitmap {
|
||||
pub header: BitmapHeader,
|
||||
pub entries: Vec<BitmapEntry>,
|
||||
}
|
||||
|
||||
impl Unpack for Bitmap {
|
||||
fn disk_size() -> u32 {
|
||||
BLOCK_SIZE as u32
|
||||
}
|
||||
|
||||
fn unpack(data: &[u8]) -> IResult<&[u8], Self> {
|
||||
let (mut i, header) = BitmapHeader::unpack(data)?;
|
||||
|
||||
let nr_words = (BLOCK_SIZE - BitmapHeader::disk_size() as usize) / 8;
|
||||
let mut entries = Vec::with_capacity(nr_words * 32);
|
||||
for _w in 0..nr_words {
|
||||
let (tmp, mut word) = le_u64(i)?;
|
||||
|
||||
for _b in 0..32 {
|
||||
let val = word & 0x3;
|
||||
word >>= 2;
|
||||
|
||||
// The bits are stored with the high bit at b * 2 + 1,
|
||||
// and low at b *2. So we have to interpret this val.
|
||||
entries.push(match val {
|
||||
0 => BitmapEntry::Small(0),
|
||||
1 => BitmapEntry::Small(2),
|
||||
2 => BitmapEntry::Small(1),
|
||||
_ => BitmapEntry::Overflow,
|
||||
});
|
||||
}
|
||||
|
||||
i = tmp;
|
||||
}
|
||||
|
||||
Ok((i, Bitmap { header, entries }))
|
||||
}
|
||||
}
|
||||
|
||||
impl Pack for Bitmap {
|
||||
fn pack<W: WriteBytesExt>(&self, out: &mut W) -> Result<()> {
|
||||
use BitmapEntry::*;
|
||||
BitmapHeader::pack(&self.header, out)?;
|
||||
|
||||
for chunk in self.entries.chunks(32) {
|
||||
let mut w = 0u64;
|
||||
for e in chunk {
|
||||
w >>= 2;
|
||||
match e {
|
||||
Small(0) => {}
|
||||
Small(1) => {
|
||||
w |= 0x2 << 62;
|
||||
}
|
||||
Small(2) => {
|
||||
w |= 0x1 << 62;
|
||||
}
|
||||
Small(_) => {
|
||||
return Err(anyhow!("Bad small value in bitmap entry"));
|
||||
}
|
||||
Overflow => {
|
||||
w |= 0x3 << 62;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
u64::pack(&w, out)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
//------------------------------------------
|
||||
|
||||
@@ -226,13 +10,22 @@ pub trait SpaceMap {
|
||||
fn get_nr_allocated(&self) -> Result<u64>;
|
||||
fn get(&self, b: u64) -> Result<u32>;
|
||||
|
||||
// Returns the old ref count
|
||||
/// Returns the old ref count
|
||||
fn set(&mut self, b: u64, v: u32) -> Result<u32>;
|
||||
|
||||
fn inc(&mut self, begin: u64, len: u64) -> Result<()>;
|
||||
|
||||
// Finds a block with a zero reference count. Increments the
|
||||
// count.
|
||||
/// Returns true if the block is now free
|
||||
fn dec(&mut self, b: u64) -> Result<bool> {
|
||||
let old = self.get(b)?;
|
||||
assert!(old > 0);
|
||||
self.set(b, old - 1)?;
|
||||
|
||||
Ok(old == 1)
|
||||
}
|
||||
|
||||
/// Finds a block with a zero reference count. Increments the
|
||||
/// count.
|
||||
fn alloc(&mut self) -> Result<Option<u64>>;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ use crate::io_engine::IoEngine;
|
||||
use crate::pdata::btree::{self, *};
|
||||
use crate::pdata::btree_walker::*;
|
||||
use crate::pdata::space_map::*;
|
||||
use crate::pdata::space_map_disk::*;
|
||||
use crate::pdata::unpack::*;
|
||||
use crate::report::Report;
|
||||
|
||||
|
||||
@@ -0,0 +1,399 @@
|
||||
use anyhow::{anyhow, Result};
|
||||
use byteorder::{LittleEndian, WriteBytesExt};
|
||||
use nom::{number::complete::*, IResult};
|
||||
use std::collections::BTreeMap;
|
||||
use std::io::Cursor;
|
||||
|
||||
use crate::checksum;
|
||||
use crate::io_engine::*;
|
||||
use crate::math::*;
|
||||
use crate::pdata::btree_builder::*;
|
||||
use crate::pdata::space_map::*;
|
||||
use crate::pdata::unpack::*;
|
||||
use crate::write_batcher::*;
|
||||
|
||||
//--------------------------------
|
||||
|
||||
const MAX_METADATA_BITMAPS: usize = 255;
|
||||
// const MAX_METADATA_BLOCKS: u64 = 255 * ((1 << 14) - 64);
|
||||
const ENTRIES_PER_BYTE: usize = 4;
|
||||
const ENTRIES_PER_BITMAP: usize = WORDS_PER_BITMAP * 8 * ENTRIES_PER_BYTE;
|
||||
|
||||
//--------------------------------
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct IndexEntry {
|
||||
pub blocknr: u64,
|
||||
pub nr_free: u32,
|
||||
pub none_free_before: u32,
|
||||
}
|
||||
|
||||
impl Unpack for IndexEntry {
|
||||
fn disk_size() -> u32 {
|
||||
16
|
||||
}
|
||||
|
||||
fn unpack(i: &[u8]) -> IResult<&[u8], IndexEntry> {
|
||||
let (i, blocknr) = le_u64(i)?;
|
||||
let (i, nr_free) = le_u32(i)?;
|
||||
let (i, none_free_before) = le_u32(i)?;
|
||||
|
||||
Ok((
|
||||
i,
|
||||
IndexEntry {
|
||||
blocknr,
|
||||
nr_free,
|
||||
none_free_before,
|
||||
},
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl Pack for IndexEntry {
|
||||
fn pack<W: WriteBytesExt>(&self, w: &mut W) -> Result<()> {
|
||||
w.write_u64::<LittleEndian>(self.blocknr)?;
|
||||
w.write_u32::<LittleEndian>(self.nr_free)?;
|
||||
w.write_u32::<LittleEndian>(self.none_free_before)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------
|
||||
|
||||
pub struct MetadataIndex {
|
||||
pub blocknr: u64,
|
||||
pub indexes: Vec<IndexEntry>,
|
||||
}
|
||||
|
||||
impl Unpack for MetadataIndex {
|
||||
fn disk_size() -> u32 {
|
||||
BLOCK_SIZE as u32
|
||||
}
|
||||
|
||||
fn unpack(i: &[u8]) -> IResult<&[u8], MetadataIndex> {
|
||||
// FIXME: check the checksum
|
||||
let (i, _csum) = le_u32(i)?;
|
||||
let (i, _padding) = le_u32(i)?;
|
||||
let (i, blocknr) = le_u64(i)?;
|
||||
let (i, indexes) = nom::multi::count(IndexEntry::unpack, MAX_METADATA_BITMAPS)(i)?;
|
||||
|
||||
Ok((i, MetadataIndex { blocknr, indexes }))
|
||||
}
|
||||
}
|
||||
|
||||
impl Pack for MetadataIndex {
|
||||
fn pack<W: WriteBytesExt>(&self, w: &mut W) -> Result<()> {
|
||||
w.write_u32::<LittleEndian>(0)?; // csum
|
||||
w.write_u32::<LittleEndian>(0)?; // padding
|
||||
w.write_u64::<LittleEndian>(self.blocknr)?;
|
||||
|
||||
assert!(self.indexes.len() <= MAX_METADATA_BITMAPS);
|
||||
|
||||
for ie in &self.indexes {
|
||||
ie.pack(w)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------
|
||||
|
||||
const WORDS_PER_BITMAP: usize = (BLOCK_SIZE - 16) / 8;
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum BitmapEntry {
|
||||
Small(u8),
|
||||
Overflow,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Bitmap {
|
||||
pub blocknr: u64,
|
||||
pub entries: Vec<BitmapEntry>,
|
||||
}
|
||||
|
||||
impl Unpack for Bitmap {
|
||||
fn disk_size() -> u32 {
|
||||
BLOCK_SIZE as u32
|
||||
}
|
||||
|
||||
fn unpack(data: &[u8]) -> IResult<&[u8], Self> {
|
||||
let (i, _csum) = le_u32(data)?;
|
||||
let (i, _not_used) = le_u32(i)?;
|
||||
let (mut i, blocknr) = le_u64(i)?;
|
||||
|
||||
let header_size = 16;
|
||||
let nr_words = (BLOCK_SIZE - header_size) / 8;
|
||||
let mut entries = Vec::with_capacity(nr_words * 32);
|
||||
for _w in 0..nr_words {
|
||||
let (tmp, mut word) = le_u64(i)?;
|
||||
|
||||
for _b in 0..32 {
|
||||
let val = word & 0x3;
|
||||
word >>= 2;
|
||||
|
||||
// The bits are stored with the high bit at b * 2 + 1,
|
||||
// and low at b *2. So we have to interpret this val.
|
||||
entries.push(match val {
|
||||
0 => BitmapEntry::Small(0),
|
||||
1 => BitmapEntry::Small(2),
|
||||
2 => BitmapEntry::Small(1),
|
||||
_ => BitmapEntry::Overflow,
|
||||
});
|
||||
}
|
||||
|
||||
i = tmp;
|
||||
}
|
||||
|
||||
Ok((i, Bitmap { blocknr, entries }))
|
||||
}
|
||||
}
|
||||
|
||||
impl Pack for Bitmap {
|
||||
fn pack<W: WriteBytesExt>(&self, out: &mut W) -> Result<()> {
|
||||
use BitmapEntry::*;
|
||||
|
||||
out.write_u32::<LittleEndian>(0)?;
|
||||
out.write_u32::<LittleEndian>(0)?;
|
||||
out.write_u64::<LittleEndian>(self.blocknr)?;
|
||||
|
||||
for chunk in self.entries.chunks(32) {
|
||||
let mut w = 0u64;
|
||||
for e in chunk {
|
||||
w >>= 2;
|
||||
match e {
|
||||
Small(0) => {}
|
||||
Small(1) => {
|
||||
w |= 0x2 << 62;
|
||||
}
|
||||
Small(2) => {
|
||||
w |= 0x1 << 62;
|
||||
}
|
||||
Small(_) => {
|
||||
return Err(anyhow!("Bad small value in bitmap entry"));
|
||||
}
|
||||
Overflow => {
|
||||
w |= 0x3 << 62;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
u64::pack(&w, out)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SMRoot {
|
||||
pub nr_blocks: u64,
|
||||
pub nr_allocated: u64,
|
||||
pub bitmap_root: u64,
|
||||
pub ref_count_root: u64,
|
||||
}
|
||||
|
||||
impl Unpack for SMRoot {
|
||||
fn disk_size() -> u32 {
|
||||
32
|
||||
}
|
||||
|
||||
fn unpack(i: &[u8]) -> IResult<&[u8], Self> {
|
||||
let (i, nr_blocks) = le_u64(i)?;
|
||||
let (i, nr_allocated) = le_u64(i)?;
|
||||
let (i, bitmap_root) = le_u64(i)?;
|
||||
let (i, ref_count_root) = le_u64(i)?;
|
||||
|
||||
Ok((
|
||||
i,
|
||||
SMRoot {
|
||||
nr_blocks,
|
||||
nr_allocated,
|
||||
bitmap_root,
|
||||
ref_count_root,
|
||||
},
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unpack_root(data: &[u8]) -> Result<SMRoot> {
|
||||
match SMRoot::unpack(data) {
|
||||
Err(_e) => Err(anyhow!("couldn't parse SMRoot")),
|
||||
Ok((_i, v)) => Ok(v),
|
||||
}
|
||||
}
|
||||
|
||||
impl Pack for SMRoot {
|
||||
fn pack<W: WriteBytesExt>(&self, w: &mut W) -> Result<()> {
|
||||
w.write_u64::<LittleEndian>(self.nr_blocks)?;
|
||||
w.write_u64::<LittleEndian>(self.nr_allocated)?;
|
||||
w.write_u64::<LittleEndian>(self.bitmap_root)?;
|
||||
w.write_u64::<LittleEndian>(self.ref_count_root)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------
|
||||
|
||||
pub fn write_common(w: &mut WriteBatcher, sm: &dyn SpaceMap) -> Result<(Vec<IndexEntry>, u64)> {
|
||||
use BitmapEntry::*;
|
||||
|
||||
let mut index_entries = Vec::new();
|
||||
let mut overflow_builder: Builder<u32> = Builder::new(Box::new(NoopRC {}));
|
||||
|
||||
// how many bitmaps do we need?
|
||||
for bm in 0..div_up(sm.get_nr_blocks()? as usize, ENTRIES_PER_BITMAP) {
|
||||
let mut entries = Vec::with_capacity(ENTRIES_PER_BITMAP);
|
||||
let mut first_free: Option<u32> = None;
|
||||
let mut nr_free: u32 = 0;
|
||||
for i in 0..ENTRIES_PER_BITMAP {
|
||||
let b: u64 = ((bm * ENTRIES_PER_BITMAP) as u64) + i as u64;
|
||||
if b > sm.get_nr_blocks()? {
|
||||
break;
|
||||
}
|
||||
let rc = sm.get(b)?;
|
||||
let e = match rc {
|
||||
0 => {
|
||||
nr_free += 1;
|
||||
if first_free.is_none() {
|
||||
first_free = Some(i as u32);
|
||||
}
|
||||
Small(0)
|
||||
}
|
||||
1 => Small(1),
|
||||
2 => Small(2),
|
||||
_ => {
|
||||
overflow_builder.push_value(w, b as u64, rc)?;
|
||||
Overflow
|
||||
}
|
||||
};
|
||||
entries.push(e);
|
||||
}
|
||||
|
||||
// allocate a new block
|
||||
let b = w.alloc()?;
|
||||
let mut cursor = Cursor::new(b.get_data());
|
||||
|
||||
// write the bitmap to it
|
||||
let blocknr = b.loc;
|
||||
let bitmap = Bitmap { blocknr, entries };
|
||||
bitmap.pack(&mut cursor)?;
|
||||
w.write(b, checksum::BT::BITMAP)?;
|
||||
|
||||
// Insert into the index tree
|
||||
let ie = IndexEntry {
|
||||
blocknr,
|
||||
nr_free,
|
||||
none_free_before: first_free.unwrap_or(ENTRIES_PER_BITMAP as u32),
|
||||
};
|
||||
index_entries.push(ie);
|
||||
}
|
||||
|
||||
let ref_count_root = overflow_builder.complete(w)?;
|
||||
Ok((index_entries, ref_count_root))
|
||||
}
|
||||
|
||||
pub fn write_disk_sm(w: &mut WriteBatcher, sm: &dyn SpaceMap) -> Result<SMRoot> {
|
||||
let (index_entries, ref_count_root) = write_common(w, sm)?;
|
||||
|
||||
let mut index_builder: Builder<IndexEntry> = Builder::new(Box::new(NoopRC {}));
|
||||
for (i, ie) in index_entries.iter().enumerate() {
|
||||
index_builder.push_value(w, i as u64, *ie)?;
|
||||
}
|
||||
|
||||
let bitmap_root = index_builder.complete(w)?;
|
||||
|
||||
Ok(SMRoot {
|
||||
nr_blocks: sm.get_nr_blocks()?,
|
||||
nr_allocated: sm.get_nr_allocated()?,
|
||||
bitmap_root,
|
||||
ref_count_root,
|
||||
})
|
||||
}
|
||||
|
||||
//----------------------------
|
||||
|
||||
fn block_to_bitmap(b: u64) -> usize {
|
||||
(b / ENTRIES_PER_BITMAP as u64) as usize
|
||||
}
|
||||
|
||||
fn adjust_counts(w: &mut WriteBatcher, ie: &IndexEntry, allocs: &[u64]) -> Result<IndexEntry> {
|
||||
use BitmapEntry::*;
|
||||
|
||||
let mut first_free = ie.none_free_before;
|
||||
let mut nr_free = ie.nr_free - allocs.len() as u32;
|
||||
|
||||
// Read the bitmap
|
||||
let bitmap_block = w.engine.read(ie.blocknr)?;
|
||||
let (_, mut bitmap) = Bitmap::unpack(bitmap_block.get_data())?;
|
||||
|
||||
// Update all the entries
|
||||
for a in allocs {
|
||||
if first_free == *a as u32 {
|
||||
first_free = *a as u32 + 1;
|
||||
}
|
||||
|
||||
if bitmap.entries[*a as usize] == Small(0) {
|
||||
nr_free -= 1;
|
||||
}
|
||||
|
||||
bitmap.entries[*a as usize] = Small(1);
|
||||
}
|
||||
|
||||
// Write the bitmap
|
||||
let mut cur = Cursor::new(bitmap_block.get_data());
|
||||
bitmap.pack(&mut cur)?;
|
||||
w.write(bitmap_block, checksum::BT::BITMAP)?;
|
||||
|
||||
// Return the adjusted index entry
|
||||
Ok(IndexEntry {
|
||||
blocknr: ie.blocknr,
|
||||
nr_free,
|
||||
none_free_before: first_free,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn write_metadata_sm(w: &mut WriteBatcher, sm: &dyn SpaceMap) -> Result<SMRoot> {
|
||||
w.clear_allocations();
|
||||
let (mut indexes, ref_count_root) = write_common(w, sm)?;
|
||||
|
||||
let bitmap_root = w.alloc()?;
|
||||
|
||||
// Now we need to patch up the counts for the metadata that was used for storing
|
||||
// the space map itself. These ref counts all went from 0 to 1.
|
||||
let allocations = w.clear_allocations();
|
||||
|
||||
// Sort the allocations by bitmap
|
||||
let mut by_bitmap = BTreeMap::new();
|
||||
for b in allocations {
|
||||
let bitmap = block_to_bitmap(b);
|
||||
(*by_bitmap.entry(bitmap).or_insert(Vec::new())).push(b % ENTRIES_PER_BITMAP as u64);
|
||||
}
|
||||
|
||||
for (bitmap, allocs) in by_bitmap {
|
||||
indexes[bitmap] = adjust_counts(w, &indexes[bitmap], &allocs)?;
|
||||
}
|
||||
|
||||
// Write out the metadata index
|
||||
let metadata_index = MetadataIndex {
|
||||
blocknr: bitmap_root.loc,
|
||||
indexes,
|
||||
};
|
||||
let mut cur = Cursor::new(bitmap_root.get_data());
|
||||
metadata_index.pack(&mut cur)?;
|
||||
let loc = bitmap_root.loc;
|
||||
w.write(bitmap_root, checksum::BT::INDEX)?;
|
||||
|
||||
Ok(SMRoot {
|
||||
nr_blocks: sm.get_nr_blocks()?,
|
||||
nr_allocated: sm.get_nr_allocated()?,
|
||||
bitmap_root: loc,
|
||||
ref_count_root,
|
||||
})
|
||||
}
|
||||
|
||||
//--------------------------------
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
use anyhow::{anyhow, Result};
|
||||
use nom::{number::complete::*, IResult};
|
||||
use byteorder::{LittleEndian, WriteBytesExt};
|
||||
use nom::{number::complete::*, IResult};
|
||||
|
||||
//------------------------------------------
|
||||
|
||||
|
||||
Reference in New Issue
Block a user