tape/helpers/snapshot_reader: sort chunks by inode (per index)

sort the chunks we want to backup to tape by inode, to gain some
speed on spinning disks. this is done per index, not globally.

costs a bit memory, but not too much, about 16 bytes per chunk which
would mean ~4MiB for a 1TiB index with 4MiB chunks.

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
This commit is contained in:
Dominik Csapak 2021-06-18 11:29:10 +02:00 committed by Dietmar Maurer
parent 4921a411ad
commit 3d3769830b
1 changed files with 13 additions and 7 deletions

View File

@ -107,7 +107,7 @@ impl SnapshotReader {
pub struct SnapshotChunkIterator<'a> { pub struct SnapshotChunkIterator<'a> {
snapshot_reader: &'a SnapshotReader, snapshot_reader: &'a SnapshotReader,
todo_list: Vec<String>, todo_list: Vec<String>,
current_index: Option<(Arc<Box<dyn IndexFile>>, usize)>, current_index: Option<(Arc<Box<dyn IndexFile + Send>>, usize, Vec<(usize, u64)>)>,
} }
impl <'a> Iterator for SnapshotChunkIterator<'a> { impl <'a> Iterator for SnapshotChunkIterator<'a> {
@ -119,20 +119,26 @@ impl <'a> Iterator for SnapshotChunkIterator<'a> {
if self.current_index.is_none() { if self.current_index.is_none() {
if let Some(filename) = self.todo_list.pop() { if let Some(filename) = self.todo_list.pop() {
let file = self.snapshot_reader.open_file(&filename)?; let file = self.snapshot_reader.open_file(&filename)?;
let index: Box<dyn IndexFile> = match archive_type(&filename)? { let index: Box<dyn IndexFile + Send> = match archive_type(&filename)? {
ArchiveType::FixedIndex => Box::new(FixedIndexReader::new(file)?), ArchiveType::FixedIndex => Box::new(FixedIndexReader::new(file)?),
ArchiveType::DynamicIndex => Box::new(DynamicIndexReader::new(file)?), ArchiveType::DynamicIndex => Box::new(DynamicIndexReader::new(file)?),
_ => bail!("SnapshotChunkIterator: got unknown file type - internal error"), _ => bail!("SnapshotChunkIterator: got unknown file type - internal error"),
}; };
self.current_index = Some((Arc::new(index), 0));
let datastore =
DataStore::lookup_datastore(self.snapshot_reader.datastore_name())?;
let order = datastore.get_chunks_in_order(&index, |_| false, |_| Ok(()))?;
self.current_index = Some((Arc::new(index), 0, order));
} else { } else {
return Ok(None); return Ok(None);
} }
} }
let (index, pos) = self.current_index.take().unwrap(); let (index, pos, list) = self.current_index.take().unwrap();
if pos < index.index_count() { if pos < list.len() {
let digest = *index.index_digest(pos).unwrap(); let (real_pos, _) = list[pos];
self.current_index = Some((index, pos + 1)); let digest = *index.index_digest(real_pos).unwrap();
self.current_index = Some((index, pos + 1, list));
return Ok(Some(digest)); return Ok(Some(digest));
} else { } else {
// pop next index // pop next index