src/backup/index.rs: add chunk_info method
This commit is contained in:
parent
b957aa81bd
commit
fdaab0df4e
@ -124,25 +124,6 @@ impl DynamicIndexReader {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::cast_ptr_alignment)]
|
|
||||||
pub fn chunk_info(&self, pos: usize) -> Result<ChunkReadInfo, Error> {
|
|
||||||
if pos >= self.index.len() {
|
|
||||||
bail!("chunk index out of range");
|
|
||||||
}
|
|
||||||
let start = if pos == 0 {
|
|
||||||
0
|
|
||||||
} else {
|
|
||||||
self.index[pos - 1].end()
|
|
||||||
};
|
|
||||||
|
|
||||||
let end = self.index[pos].end();
|
|
||||||
|
|
||||||
Ok(ChunkReadInfo {
|
|
||||||
range: start..end,
|
|
||||||
digest: self.index[pos].digest.clone(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
#[allow(clippy::cast_ptr_alignment)]
|
#[allow(clippy::cast_ptr_alignment)]
|
||||||
fn chunk_end(&self, pos: usize) -> u64 {
|
fn chunk_end(&self, pos: usize) -> u64 {
|
||||||
@ -225,6 +206,21 @@ impl IndexFile for DynamicIndexReader {
|
|||||||
self.chunk_end(self.index.len() - 1)
|
self.chunk_end(self.index.len() - 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::cast_ptr_alignment)]
|
||||||
|
fn chunk_info(&self, pos: usize) -> Option<ChunkReadInfo> {
|
||||||
|
if pos >= self.index.len() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let start = if pos == 0 { 0 } else { self.index[pos - 1].end() };
|
||||||
|
|
||||||
|
let end = self.index[pos].end();
|
||||||
|
|
||||||
|
Some(ChunkReadInfo {
|
||||||
|
range: start..end,
|
||||||
|
digest: self.index[pos].digest.clone(),
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CachedChunk {
|
struct CachedChunk {
|
||||||
@ -264,7 +260,10 @@ struct ChunkCacher<'a, S> {
|
|||||||
|
|
||||||
impl<'a, S: ReadChunk> crate::tools::lru_cache::Cacher<usize, CachedChunk> for ChunkCacher<'a, S> {
|
impl<'a, S: ReadChunk> crate::tools::lru_cache::Cacher<usize, CachedChunk> for ChunkCacher<'a, S> {
|
||||||
fn fetch(&mut self, index: usize) -> Result<Option<CachedChunk>, Error> {
|
fn fetch(&mut self, index: usize) -> Result<Option<CachedChunk>, Error> {
|
||||||
let info = self.index.chunk_info(index)?;
|
let info = match self.index.chunk_info(index) {
|
||||||
|
Some(info) => info,
|
||||||
|
None => bail!("chunk index out of range"),
|
||||||
|
};
|
||||||
let range = info.range;
|
let range = info.range;
|
||||||
let data = self.store.read_chunk(&info.digest)?;
|
let data = self.store.read_chunk(&info.digest)?;
|
||||||
CachedChunk::new(range, data).map(Some)
|
CachedChunk::new(range, data).map(Some)
|
||||||
|
@ -4,7 +4,7 @@ use std::io::{Seek, SeekFrom};
|
|||||||
|
|
||||||
use super::chunk_stat::*;
|
use super::chunk_stat::*;
|
||||||
use super::chunk_store::*;
|
use super::chunk_store::*;
|
||||||
use super::IndexFile;
|
use super::{IndexFile, ChunkReadInfo};
|
||||||
use crate::tools::{self, epoch_now_u64};
|
use crate::tools::{self, epoch_now_u64};
|
||||||
|
|
||||||
use chrono::{Local, TimeZone};
|
use chrono::{Local, TimeZone};
|
||||||
@ -147,29 +147,6 @@ impl FixedIndexReader {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn chunk_info(&self, pos: usize) -> Result<(u64, u64, [u8; 32]), Error> {
|
|
||||||
if pos >= self.index_length {
|
|
||||||
bail!("chunk index out of range");
|
|
||||||
}
|
|
||||||
let start = (pos * self.chunk_size) as u64;
|
|
||||||
let mut end = start + self.chunk_size as u64;
|
|
||||||
|
|
||||||
if end > self.size {
|
|
||||||
end = self.size;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut digest = std::mem::MaybeUninit::<[u8; 32]>::uninit();
|
|
||||||
unsafe {
|
|
||||||
std::ptr::copy_nonoverlapping(
|
|
||||||
self.index.add(pos * 32),
|
|
||||||
(*digest.as_mut_ptr()).as_mut_ptr(),
|
|
||||||
32,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok((start, end, unsafe { digest.assume_init() }))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn chunk_digest(&self, pos: usize) -> &[u8; 32] {
|
fn chunk_digest(&self, pos: usize) -> &[u8; 32] {
|
||||||
if pos >= self.index_length {
|
if pos >= self.index_length {
|
||||||
@ -234,6 +211,25 @@ impl IndexFile for FixedIndexReader {
|
|||||||
fn index_bytes(&self) -> u64 {
|
fn index_bytes(&self) -> u64 {
|
||||||
self.size
|
self.size
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn chunk_info(&self, pos: usize) -> Option<ChunkReadInfo> {
|
||||||
|
if pos >= self.index_length {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let start = (pos * self.chunk_size) as u64;
|
||||||
|
let mut end = start + self.chunk_size as u64;
|
||||||
|
|
||||||
|
if end > self.size {
|
||||||
|
end = self.size;
|
||||||
|
}
|
||||||
|
|
||||||
|
let digest = self.index_digest(pos).unwrap();
|
||||||
|
Some(ChunkReadInfo {
|
||||||
|
range: start..end,
|
||||||
|
digest: *digest,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct FixedIndexWriter {
|
pub struct FixedIndexWriter {
|
||||||
@ -511,18 +507,17 @@ impl<S: ReadChunk> BufferedFixedReader<S> {
|
|||||||
|
|
||||||
fn buffer_chunk(&mut self, idx: usize) -> Result<(), Error> {
|
fn buffer_chunk(&mut self, idx: usize) -> Result<(), Error> {
|
||||||
let index = &self.index;
|
let index = &self.index;
|
||||||
let (start, end, digest) = index.chunk_info(idx)?;
|
let info = match index.chunk_info(idx) {
|
||||||
|
Some(info) => info,
|
||||||
|
None => bail!("chunk index out of range"),
|
||||||
|
};
|
||||||
|
|
||||||
// fixme: avoid copy
|
// fixme: avoid copy
|
||||||
|
|
||||||
let data = self.store.read_chunk(&digest)?;
|
let data = self.store.read_chunk(&info.digest)?;
|
||||||
|
let size = info.range.end - info.range.start;
|
||||||
if (end - start) != data.len() as u64 {
|
if size != data.len() as u64 {
|
||||||
bail!(
|
bail!("read chunk with wrong size ({} != {}", size, data.len());
|
||||||
"read chunk with wrong size ({} != {}",
|
|
||||||
(end - start),
|
|
||||||
data.len()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.read_buffer.clear();
|
self.read_buffer.clear();
|
||||||
@ -530,8 +525,7 @@ impl<S: ReadChunk> BufferedFixedReader<S> {
|
|||||||
|
|
||||||
self.buffered_chunk_idx = idx;
|
self.buffered_chunk_idx = idx;
|
||||||
|
|
||||||
self.buffered_chunk_start = start as u64;
|
self.buffered_chunk_start = info.range.start as u64;
|
||||||
//println!("BUFFER {} {}", self.buffered_chunk_start, end);
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@ pub trait IndexFile {
|
|||||||
fn index_count(&self) -> usize;
|
fn index_count(&self) -> usize;
|
||||||
fn index_digest(&self, pos: usize) -> Option<&[u8; 32]>;
|
fn index_digest(&self, pos: usize) -> Option<&[u8; 32]>;
|
||||||
fn index_bytes(&self) -> u64;
|
fn index_bytes(&self) -> u64;
|
||||||
|
fn chunk_info(&self, pos: usize) -> Option<ChunkReadInfo>;
|
||||||
|
|
||||||
/// Returns most often used chunks
|
/// Returns most often used chunks
|
||||||
fn find_most_used_chunks(&self, max: usize) -> HashMap<[u8; 32], usize> {
|
fn find_most_used_chunks(&self, max: usize) -> HashMap<[u8; 32], usize> {
|
||||||
|
@ -34,6 +34,25 @@ fn verify_blob(datastore: &DataStore, backup_dir: &BackupDir, info: &FileInfo) -
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn verify_index_chunks(
|
||||||
|
datastore: &DataStore,
|
||||||
|
index: Box<dyn IndexFile>,
|
||||||
|
worker: &WorkerTask,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
|
||||||
|
for pos in 0..index.index_count() {
|
||||||
|
|
||||||
|
worker.fail_on_abort()?;
|
||||||
|
crate::tools::fail_on_shutdown()?;
|
||||||
|
|
||||||
|
let info = index.chunk_info(pos).unwrap();
|
||||||
|
let size = info.range.end - info.range.start;
|
||||||
|
datastore.verify_stored_chunk(&info.digest, size)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn verify_fixed_index(datastore: &DataStore, backup_dir: &BackupDir, info: &FileInfo, worker: &WorkerTask) -> Result<(), Error> {
|
fn verify_fixed_index(datastore: &DataStore, backup_dir: &BackupDir, info: &FileInfo, worker: &WorkerTask) -> Result<(), Error> {
|
||||||
|
|
||||||
let mut path = backup_dir.relative_path();
|
let mut path = backup_dir.relative_path();
|
||||||
@ -50,17 +69,7 @@ fn verify_fixed_index(datastore: &DataStore, backup_dir: &BackupDir, info: &File
|
|||||||
bail!("wrong index checksum");
|
bail!("wrong index checksum");
|
||||||
}
|
}
|
||||||
|
|
||||||
for pos in 0..index.index_count() {
|
verify_index_chunks(datastore, Box::new(index), worker)
|
||||||
|
|
||||||
worker.fail_on_abort()?;
|
|
||||||
crate::tools::fail_on_shutdown()?;
|
|
||||||
|
|
||||||
let (start, end, digest) = index.chunk_info(pos).unwrap();
|
|
||||||
let size = end - start;
|
|
||||||
datastore.verify_stored_chunk(&digest, size)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn verify_dynamic_index(datastore: &DataStore, backup_dir: &BackupDir, info: &FileInfo, worker: &WorkerTask) -> Result<(), Error> {
|
fn verify_dynamic_index(datastore: &DataStore, backup_dir: &BackupDir, info: &FileInfo, worker: &WorkerTask) -> Result<(), Error> {
|
||||||
@ -78,17 +87,7 @@ fn verify_dynamic_index(datastore: &DataStore, backup_dir: &BackupDir, info: &Fi
|
|||||||
bail!("wrong index checksum");
|
bail!("wrong index checksum");
|
||||||
}
|
}
|
||||||
|
|
||||||
for pos in 0..index.index_count() {
|
verify_index_chunks(datastore, Box::new(index), worker)
|
||||||
|
|
||||||
worker.fail_on_abort()?;
|
|
||||||
crate::tools::fail_on_shutdown()?;
|
|
||||||
|
|
||||||
let chunk_info = index.chunk_info(pos).unwrap();
|
|
||||||
let size = chunk_info.range.end - chunk_info.range.start;
|
|
||||||
datastore.verify_stored_chunk(&chunk_info.digest, size)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Verify a single backup snapshot
|
/// Verify a single backup snapshot
|
||||||
|
Loading…
Reference in New Issue
Block a user