Skip to content

Commit 4f84cf7

Browse files
committed
Check hashes during repair
1 parent 4c3080a commit 4f84cf7

File tree

3 files changed

+64
-4
lines changed

3 files changed

+64
-4
lines changed

downstairs/src/extent.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,22 @@ pub fn extent_dir<P: AsRef<Path>>(dir: P, number: ExtentId) -> PathBuf {
251251
* anchored under "dir".
252252
*/
253253
pub fn extent_path<P: AsRef<Path>>(dir: P, number: ExtentId) -> PathBuf {
254-
extent_dir(dir, number).join(extent_file_name(number, ExtentType::Data))
254+
let e = extent_file_name(number, ExtentType::Data);
255+
256+
// XXX terrible hack: if someone has already provided a full directory tree
257+
// ending in `.copy`, then just append the extent file name. This lets us
258+
// open individual extent files during live-repair.
259+
if dir
260+
.as_ref()
261+
.iter()
262+
.next_back()
263+
.and_then(|s| s.to_str())
264+
.is_some_and(|s| s.ends_with(".copy"))
265+
{
266+
dir.as_ref().join(e)
267+
} else {
268+
extent_dir(dir, number).join(e)
269+
}
255270
}
256271

257272
/**

downstairs/src/extent_inner_sqlite.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -104,9 +104,8 @@ impl ExtentInner for SqliteInner {
104104
}
105105

106106
fn validate(&self) -> Result<(), CrucibleError> {
107-
Err(CrucibleError::GenericError(
108-
"`validate` is not implemented for Sqlite extent".to_owned(),
109-
))
107+
// SQLite databases are always perfect and have no problems
108+
Ok(())
110109
}
111110

112111
#[cfg(test)]

downstairs/src/region.rs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,30 @@ impl Region {
400400
assert_eq!(self.get_opened_extent(eid).number, eid);
401401
}
402402
assert_eq!(self.def.extent_count() as usize, self.extents.len());
403+
use rayon::prelude::*;
404+
let errors: Vec<_> = self
405+
.extents
406+
.par_iter()
407+
.filter_map(|e| {
408+
let ExtentState::Opened(extent) = e else {
409+
unreachable!("got closed extent");
410+
};
411+
if let Err(err) = extent.validate() {
412+
Some((extent.number, err))
413+
} else {
414+
None
415+
}
416+
})
417+
.collect();
418+
if !errors.is_empty() {
419+
for (number, err) in &errors {
420+
warn!(
421+
self.log,
422+
"validation falied for extent {number}: {err:?}"
423+
);
424+
}
425+
panic!("validation failed");
426+
}
403427
}
404428

405429
/// Walk the list of extents and close each one.
@@ -682,6 +706,28 @@ impl Region {
682706
);
683707
}
684708

709+
// Validate the extent that we just received, before copying it over
710+
{
711+
let new_extent = match Extent::open(
712+
&copy_dir,
713+
&self.def(),
714+
eid,
715+
true, // read-only
716+
&self.log.clone(),
717+
) {
718+
Ok(e) => e,
719+
Err(e) => {
720+
panic!(
721+
"Failed to open live-repair extent {eid} in \
722+
{copy_dir:?}: {e:?}"
723+
);
724+
}
725+
};
726+
if let Err(e) = new_extent.validate() {
727+
panic!("Failed to validate live-repair extent {eid}: {e:?}");
728+
}
729+
}
730+
685731
// After we have all files: move the repair dir.
686732
info!(
687733
self.log,

0 commit comments

Comments
 (0)