2021-03-24 19:50:20 +05:30
|
|
|
use anyhow::{anyhow, Result};
|
2020-12-09 18:52:32 +05:30
|
|
|
|
2021-03-24 19:50:20 +05:30
|
|
|
use std::collections::BTreeMap;
|
2020-12-09 18:52:32 +05:30
|
|
|
use std::fs::OpenOptions;
|
2021-05-26 18:48:53 +05:30
|
|
|
use std::io::Cursor;
|
|
|
|
use std::ops::Deref;
|
2020-10-26 17:35:27 +05:30
|
|
|
use std::path::Path;
|
2021-05-26 18:48:53 +05:30
|
|
|
use std::sync::{Arc, Mutex};
|
2020-10-26 17:35:27 +05:30
|
|
|
|
2021-03-24 19:50:20 +05:30
|
|
|
use crate::io_engine::*;
|
|
|
|
use crate::pdata::btree_builder::*;
|
|
|
|
use crate::pdata::space_map::*;
|
2021-05-26 18:48:53 +05:30
|
|
|
use crate::pdata::space_map_disk::*;
|
|
|
|
use crate::pdata::space_map_metadata::*;
|
|
|
|
use crate::pdata::unpack::Pack;
|
2020-10-26 17:35:27 +05:30
|
|
|
use crate::report::*;
|
2020-12-09 18:52:32 +05:30
|
|
|
use crate::thin::block_time::*;
|
|
|
|
use crate::thin::device_detail::*;
|
2021-03-24 19:50:20 +05:30
|
|
|
use crate::thin::superblock::{self, *};
|
2020-12-09 18:52:32 +05:30
|
|
|
use crate::thin::xml::{self, *};
|
2021-03-24 19:50:20 +05:30
|
|
|
use crate::write_batcher::*;
|
2020-12-09 18:52:32 +05:30
|
|
|
|
|
|
|
//------------------------------------------
|
|
|
|
|
2021-05-26 18:48:53 +05:30
|
|
|
struct MappingRC {
|
|
|
|
sm: Arc<Mutex<dyn SpaceMap>>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl RefCounter<BlockTime> for MappingRC {
|
|
|
|
fn get(&self, v: &BlockTime) -> Result<u32> {
|
|
|
|
return self.sm.lock().unwrap().get(v.block);
|
|
|
|
}
|
|
|
|
fn inc(&mut self, v: &BlockTime) -> Result<()> {
|
|
|
|
self.sm.lock().unwrap().inc(v.block, 1)
|
|
|
|
}
|
|
|
|
fn dec(&mut self, v: &BlockTime) -> Result<()> {
|
|
|
|
self.sm.lock().unwrap().dec(v.block)?;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------
|
|
|
|
|
2021-03-24 19:50:20 +05:30
|
|
|
enum MappedSection {
|
|
|
|
Def(String),
|
|
|
|
Dev(u32),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl std::fmt::Display for MappedSection {
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
|
|
match self {
|
|
|
|
MappedSection::Def(name) => write!(f, "Def {}", name),
|
|
|
|
MappedSection::Dev(thin_id) => write!(f, "Device {}", thin_id),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-26 18:48:53 +05:30
|
|
|
//------------------------------------------
|
|
|
|
|
2021-06-10 21:48:18 +05:30
|
|
|
struct RestoreResult {
|
2021-05-18 19:32:49 +05:30
|
|
|
sb: xml::Superblock,
|
2021-06-10 21:48:18 +05:30
|
|
|
devices: BTreeMap<u32, (DeviceDetail, u64)>,
|
2021-05-26 18:48:53 +05:30
|
|
|
data_sm: Arc<Mutex<dyn SpaceMap>>,
|
2021-03-24 19:50:20 +05:30
|
|
|
}
|
|
|
|
|
2021-06-10 21:48:18 +05:30
|
|
|
struct Restorer<'a> {
|
2021-03-24 19:50:20 +05:30
|
|
|
w: &'a mut WriteBatcher,
|
2021-06-10 21:48:18 +05:30
|
|
|
report: Arc<Report>,
|
2021-03-24 19:50:20 +05:30
|
|
|
|
2021-06-10 21:48:18 +05:30
|
|
|
// Shared leaves built from the <def> tags
|
2021-03-24 19:50:20 +05:30
|
|
|
sub_trees: BTreeMap<String, Vec<NodeSummary>>,
|
|
|
|
|
|
|
|
// The builder for the current shared sub tree or device
|
2021-06-10 21:48:18 +05:30
|
|
|
current_map: Option<(MappedSection, NodeBuilder<BlockTime>)>,
|
|
|
|
current_dev: Option<DeviceDetail>,
|
2021-03-24 19:50:20 +05:30
|
|
|
|
2021-05-18 19:32:49 +05:30
|
|
|
sb: Option<xml::Superblock>,
|
2021-06-10 21:48:18 +05:30
|
|
|
devices: BTreeMap<u32, (DeviceDetail, u64)>,
|
2021-05-26 18:48:53 +05:30
|
|
|
data_sm: Option<Arc<Mutex<dyn SpaceMap>>>,
|
2021-03-24 19:50:20 +05:30
|
|
|
}
|
|
|
|
|
2021-06-10 21:48:18 +05:30
|
|
|
impl<'a> Restorer<'a> {
|
|
|
|
fn new(w: &'a mut WriteBatcher, report: Arc<Report>) -> Self {
|
|
|
|
Restorer {
|
2021-03-24 19:50:20 +05:30
|
|
|
w,
|
2021-06-10 21:48:18 +05:30
|
|
|
report,
|
2021-03-24 19:50:20 +05:30
|
|
|
sub_trees: BTreeMap::new(),
|
2021-06-10 21:48:18 +05:30
|
|
|
current_map: None,
|
|
|
|
current_dev: None,
|
2021-05-18 19:32:49 +05:30
|
|
|
sb: None,
|
|
|
|
devices: BTreeMap::new(),
|
2021-05-26 18:48:53 +05:30
|
|
|
data_sm: None,
|
2021-03-24 19:50:20 +05:30
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-10 21:48:18 +05:30
|
|
|
fn get_result(self) -> Result<RestoreResult> {
|
2021-05-18 19:32:49 +05:30
|
|
|
if self.sb.is_none() {
|
|
|
|
return Err(anyhow!("No superblock found in xml file"));
|
|
|
|
}
|
2021-06-10 21:48:18 +05:30
|
|
|
Ok(RestoreResult {
|
2021-05-18 19:32:49 +05:30
|
|
|
sb: self.sb.unwrap(),
|
|
|
|
devices: self.devices,
|
2021-05-26 18:48:53 +05:30
|
|
|
data_sm: self.data_sm.unwrap(),
|
2021-05-18 19:32:49 +05:30
|
|
|
})
|
2021-03-24 19:50:20 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
fn begin_section(&mut self, section: MappedSection) -> Result<Visit> {
|
2021-06-10 21:48:18 +05:30
|
|
|
if let Some((outer, _)) = self.current_map.as_ref() {
|
2021-03-24 19:50:20 +05:30
|
|
|
let msg = format!(
|
|
|
|
"Nested subtrees are not allowed '{}' within '{}'",
|
|
|
|
section, outer
|
|
|
|
);
|
|
|
|
return Err(anyhow!(msg));
|
|
|
|
}
|
|
|
|
|
2021-05-26 18:48:53 +05:30
|
|
|
let value_rc = Box::new(MappingRC {
|
|
|
|
sm: self.data_sm.as_ref().unwrap().clone(),
|
|
|
|
});
|
2021-03-24 19:50:20 +05:30
|
|
|
let leaf_builder = NodeBuilder::new(Box::new(LeafIO {}), value_rc);
|
|
|
|
|
2021-06-10 21:48:18 +05:30
|
|
|
self.current_map = Some((section, leaf_builder));
|
2021-03-24 19:50:20 +05:30
|
|
|
Ok(Visit::Continue)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn end_section(&mut self) -> Result<(MappedSection, Vec<NodeSummary>)> {
|
|
|
|
let mut current = None;
|
2021-06-10 21:48:18 +05:30
|
|
|
std::mem::swap(&mut self.current_map, &mut current);
|
2021-03-24 19:50:20 +05:30
|
|
|
|
|
|
|
if let Some((name, nodes)) = current {
|
|
|
|
Ok((name, nodes.complete(self.w)?))
|
|
|
|
} else {
|
2021-06-10 21:48:18 +05:30
|
|
|
let msg = "Unbalanced </def> or </device> tag".to_string();
|
2021-03-24 19:50:20 +05:30
|
|
|
Err(anyhow!(msg))
|
|
|
|
}
|
|
|
|
}
|
2020-12-09 18:52:32 +05:30
|
|
|
}
|
|
|
|
|
2021-06-10 21:48:18 +05:30
|
|
|
impl<'a> MetadataVisitor for Restorer<'a> {
|
2020-12-09 18:52:32 +05:30
|
|
|
fn superblock_b(&mut self, sb: &xml::Superblock) -> Result<Visit> {
|
2021-05-18 19:32:49 +05:30
|
|
|
self.sb = Some(sb.clone());
|
2021-05-26 18:48:53 +05:30
|
|
|
self.data_sm = Some(core_sm(sb.nr_data_blocks, u32::MAX));
|
2021-05-02 21:21:56 +05:30
|
|
|
self.w.alloc()?;
|
2021-03-24 19:50:20 +05:30
|
|
|
Ok(Visit::Continue)
|
2020-12-09 18:52:32 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
fn superblock_e(&mut self) -> Result<Visit> {
|
2021-03-24 19:50:20 +05:30
|
|
|
Ok(Visit::Continue)
|
2020-12-09 18:52:32 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
fn def_shared_b(&mut self, name: &str) -> Result<Visit> {
|
2021-03-24 19:50:20 +05:30
|
|
|
self.begin_section(MappedSection::Def(name.to_string()))
|
2020-12-09 18:52:32 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
fn def_shared_e(&mut self) -> Result<Visit> {
|
2021-03-24 19:50:20 +05:30
|
|
|
if let (MappedSection::Def(name), nodes) = self.end_section()? {
|
|
|
|
self.sub_trees.insert(name, nodes);
|
|
|
|
Ok(Visit::Continue)
|
|
|
|
} else {
|
|
|
|
Err(anyhow!("unexpected </def>"))
|
|
|
|
}
|
2020-12-09 18:52:32 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
fn device_b(&mut self, d: &Device) -> Result<Visit> {
|
2021-06-10 21:48:18 +05:30
|
|
|
self.report
|
|
|
|
.info(&format!("building btree for device {}", d.dev_id));
|
2021-03-24 19:50:20 +05:30
|
|
|
self.current_dev = Some(DeviceDetail {
|
|
|
|
mapped_blocks: d.mapped_blocks,
|
|
|
|
transaction_id: d.transaction,
|
|
|
|
creation_time: d.creation_time as u32,
|
|
|
|
snapshotted_time: d.snap_time as u32,
|
|
|
|
});
|
|
|
|
self.begin_section(MappedSection::Dev(d.dev_id))
|
2020-12-09 18:52:32 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
fn device_e(&mut self) -> Result<Visit> {
|
2021-03-24 19:50:20 +05:30
|
|
|
if let Some(detail) = self.current_dev.take() {
|
|
|
|
if let (MappedSection::Dev(thin_id), nodes) = self.end_section()? {
|
2021-06-10 21:48:18 +05:30
|
|
|
let root = build_btree(self.w, nodes)?;
|
|
|
|
self.devices.insert(thin_id, (detail, root));
|
2021-03-24 19:50:20 +05:30
|
|
|
Ok(Visit::Continue)
|
|
|
|
} else {
|
|
|
|
Err(anyhow!("internal error, couldn't find device details"))
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
Err(anyhow!("unexpected </device>"))
|
|
|
|
}
|
2020-12-09 18:52:32 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
fn map(&mut self, m: &Map) -> Result<Visit> {
|
2021-06-10 21:48:18 +05:30
|
|
|
if let Some((_, builder)) = self.current_map.as_mut() {
|
2021-03-24 19:50:20 +05:30
|
|
|
for i in 0..m.len {
|
|
|
|
let bt = BlockTime {
|
|
|
|
block: m.data_begin + i,
|
|
|
|
time: m.time,
|
|
|
|
};
|
|
|
|
builder.push_value(self.w, m.thin_begin + i, bt)?;
|
|
|
|
}
|
|
|
|
Ok(Visit::Continue)
|
|
|
|
} else {
|
2021-05-11 18:11:30 +05:30
|
|
|
let msg = "Mapping tags must appear within a <def> or <device> tag.".to_string();
|
2021-03-24 19:50:20 +05:30
|
|
|
Err(anyhow!(msg))
|
|
|
|
}
|
2020-12-09 18:52:32 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
fn ref_shared(&mut self, name: &str) -> Result<Visit> {
|
2021-03-24 19:50:20 +05:30
|
|
|
if self.current_dev.is_none() {
|
|
|
|
return Err(anyhow!(
|
|
|
|
"<ref> tags may only occur within <device> sections."
|
|
|
|
));
|
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(leaves) = self.sub_trees.get(name) {
|
|
|
|
// We could be in a <def> or <device>
|
2021-06-10 21:48:18 +05:30
|
|
|
if let Some((_name, builder)) = self.current_map.as_mut() {
|
2021-03-24 19:50:20 +05:30
|
|
|
builder.push_nodes(self.w, leaves)?;
|
|
|
|
} else {
|
|
|
|
let msg = format!(
|
|
|
|
"<ref name=\"{}\"> tag must be within either a <def> or <device> section",
|
|
|
|
name
|
|
|
|
);
|
|
|
|
return Err(anyhow!(msg));
|
|
|
|
}
|
|
|
|
Ok(Visit::Continue)
|
|
|
|
} else {
|
|
|
|
let msg = format!("Couldn't find sub tree '{}'.", name);
|
|
|
|
Err(anyhow!(msg))
|
|
|
|
}
|
2020-12-09 18:52:32 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
fn eof(&mut self) -> Result<Visit> {
|
2021-03-24 19:50:20 +05:30
|
|
|
// FIXME: build the rest of the device trees
|
|
|
|
Ok(Visit::Continue)
|
2020-12-09 18:52:32 +05:30
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-24 19:50:20 +05:30
|
|
|
//------------------------------------------
|
2021-05-26 18:48:53 +05:30
|
|
|
|
2021-03-24 19:50:20 +05:30
|
|
|
/// Writes a data space map to disk. Returns the space map root that needs
|
|
|
|
/// to be written to the superblock.
|
2021-05-26 18:48:53 +05:30
|
|
|
fn build_data_sm(w: &mut WriteBatcher, sm: &dyn SpaceMap) -> Result<Vec<u8>> {
|
|
|
|
let mut sm_root = vec![0u8; SPACE_MAP_ROOT_SIZE];
|
|
|
|
let mut cur = Cursor::new(&mut sm_root);
|
|
|
|
let r = write_disk_sm(w, sm)?;
|
|
|
|
r.pack(&mut cur)?;
|
2021-03-24 19:50:20 +05:30
|
|
|
|
2021-05-26 18:48:53 +05:30
|
|
|
Ok(sm_root)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Writes the metadata space map to disk. Returns the space map root that needs
|
|
|
|
/// to be written to the superblock.
|
|
|
|
fn build_metadata_sm(w: &mut WriteBatcher) -> Result<Vec<u8>> {
|
|
|
|
let mut sm_root = vec![0u8; SPACE_MAP_ROOT_SIZE];
|
|
|
|
let mut cur = Cursor::new(&mut sm_root);
|
|
|
|
let sm_without_meta = clone_space_map(w.sm.lock().unwrap().deref())?;
|
|
|
|
let r = write_metadata_sm(w, sm_without_meta.deref())?;
|
|
|
|
r.pack(&mut cur)?;
|
|
|
|
|
|
|
|
Ok(sm_root)
|
2021-03-24 19:50:20 +05:30
|
|
|
}
|
|
|
|
|
2020-10-26 17:35:27 +05:30
|
|
|
//------------------------------------------
|
|
|
|
|
|
|
|
pub struct ThinRestoreOptions<'a> {
|
|
|
|
pub input: &'a Path,
|
|
|
|
pub output: &'a Path,
|
|
|
|
pub async_io: bool,
|
|
|
|
pub report: Arc<Report>,
|
|
|
|
}
|
|
|
|
|
2021-03-24 19:50:20 +05:30
|
|
|
struct Context {
|
|
|
|
report: Arc<Report>,
|
|
|
|
engine: Arc<dyn IoEngine + Send + Sync>,
|
|
|
|
}
|
|
|
|
|
|
|
|
const MAX_CONCURRENT_IO: u32 = 1024;
|
|
|
|
|
|
|
|
fn new_context(opts: &ThinRestoreOptions) -> Result<Context> {
|
|
|
|
let engine: Arc<dyn IoEngine + Send + Sync>;
|
|
|
|
|
|
|
|
if opts.async_io {
|
|
|
|
engine = Arc::new(AsyncIoEngine::new(opts.output, MAX_CONCURRENT_IO, true)?);
|
|
|
|
} else {
|
|
|
|
let nr_threads = std::cmp::max(8, num_cpus::get() * 2);
|
|
|
|
engine = Arc::new(SyncIoEngine::new(opts.output, nr_threads, true)?);
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(Context {
|
|
|
|
report: opts.report.clone(),
|
|
|
|
engine,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-10-26 17:35:27 +05:30
|
|
|
//------------------------------------------
|
|
|
|
|
2020-12-09 18:52:32 +05:30
|
|
|
pub fn restore(opts: ThinRestoreOptions) -> Result<()> {
|
|
|
|
let input = OpenOptions::new()
|
|
|
|
.read(true)
|
|
|
|
.write(false)
|
|
|
|
.open(opts.input)?;
|
|
|
|
|
2021-03-24 19:50:20 +05:30
|
|
|
let ctx = new_context(&opts)?;
|
|
|
|
let max_count = u32::MAX;
|
|
|
|
|
|
|
|
let sm = core_sm(ctx.engine.get_nr_blocks(), max_count);
|
|
|
|
let mut w = WriteBatcher::new(ctx.engine.clone(), sm.clone(), ctx.engine.get_batch_size());
|
2021-06-10 21:48:18 +05:30
|
|
|
let mut restorer = Restorer::new(&mut w, ctx.report.clone());
|
|
|
|
xml::read(input, &mut restorer)?;
|
|
|
|
let result = restorer.get_result()?;
|
2021-03-24 19:50:20 +05:30
|
|
|
|
2021-06-10 21:48:18 +05:30
|
|
|
// Build the device details and top level mapping tree
|
2021-06-10 14:25:25 +05:30
|
|
|
let mut details_builder: BTreeBuilder<DeviceDetail> = BTreeBuilder::new(Box::new(NoopRC {}));
|
2021-06-10 21:48:18 +05:30
|
|
|
let mut dev_builder: BTreeBuilder<u64> = BTreeBuilder::new(Box::new(NoopRC {}));
|
|
|
|
for (thin_id, (detail, root)) in &result.devices {
|
2021-03-24 19:50:20 +05:30
|
|
|
details_builder.push_value(&mut w, *thin_id as u64, *detail)?;
|
2021-06-10 21:48:18 +05:30
|
|
|
dev_builder.push_value(&mut w, *thin_id as u64, *root)?;
|
2021-03-24 19:50:20 +05:30
|
|
|
}
|
|
|
|
let details_root = details_builder.complete(&mut w)?;
|
2021-06-10 21:48:18 +05:30
|
|
|
let mapping_root = dev_builder.complete(&mut w)?;
|
2021-03-24 19:50:20 +05:30
|
|
|
|
|
|
|
// Build data space map
|
2021-06-10 21:48:18 +05:30
|
|
|
let data_sm_root = build_data_sm(&mut w, result.data_sm.lock().unwrap().deref())?;
|
2021-03-24 19:50:20 +05:30
|
|
|
|
|
|
|
// Build metadata space map
|
2021-05-26 18:48:53 +05:30
|
|
|
let metadata_sm_root = build_metadata_sm(&mut w)?;
|
2021-05-02 21:21:56 +05:30
|
|
|
|
2021-03-24 19:50:20 +05:30
|
|
|
// Write the superblock
|
2021-05-18 19:32:49 +05:30
|
|
|
let sb = superblock::Superblock {
|
|
|
|
flags: SuperblockFlags { needs_check: false },
|
|
|
|
block: SUPERBLOCK_LOCATION,
|
|
|
|
version: 2,
|
2021-06-10 21:48:18 +05:30
|
|
|
time: result.sb.time as u32,
|
|
|
|
transaction_id: result.sb.transaction,
|
2021-05-18 19:32:49 +05:30
|
|
|
metadata_snap: 0,
|
2021-05-26 18:48:53 +05:30
|
|
|
data_sm_root,
|
|
|
|
metadata_sm_root,
|
2021-05-18 19:32:49 +05:30
|
|
|
mapping_root,
|
|
|
|
details_root,
|
2021-06-10 21:48:18 +05:30
|
|
|
data_block_size: result.sb.data_block_size,
|
2021-05-18 19:32:49 +05:30
|
|
|
nr_metadata_blocks: ctx.engine.get_nr_blocks(),
|
|
|
|
};
|
|
|
|
write_superblock(ctx.engine.as_ref(), SUPERBLOCK_LOCATION, &sb)?;
|
2020-12-09 18:52:32 +05:30
|
|
|
|
|
|
|
Ok(())
|
2020-10-26 17:35:27 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------
|