Skip to content

Commit 4ea5326

Browse files
committed
add Error::Unrecoverable
1 parent 0eeaa6f commit 4ea5326

File tree

3 files changed

+74
-1
lines changed

3 files changed

+74
-1
lines changed

src/error.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ pub enum Error {
2828

2929
/// Decompression failed
3030
Decompress,
31+
32+
/// Some required segments could not be recovered from disk
33+
Unrecoverable,
3134
// TODO:
3235
// /// Checksum check failed
3336
// ChecksumMismatch,
@@ -45,7 +48,9 @@ impl std::error::Error for Error {
4548
Self::Io(e) => Some(e),
4649
Self::Encode(e) => Some(e),
4750
Self::Decode(e) => Some(e),
48-
Self::Decompress | Self::InvalidVersion(_) | Self::Compress => None,
51+
Self::Decompress | Self::InvalidVersion(_) | Self::Compress | Self::Unrecoverable => {
52+
None
53+
}
4954
}
5055
}
5156
}

src/manifest.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,10 @@ impl<C: Compressor + Clone> SegmentManifest<C> {
159159
map
160160
};
161161

162+
if segments.len() < ids.len() {
163+
return Err(crate::Error::Unrecoverable);
164+
}
165+
162166
Ok(Self(Arc::new(SegmentManifestInner {
163167
path: manifest_path,
164168
segments: RwLock::new(segments),

tests/recovery_fail.rs

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
use test_log::test;
2+
use value_log::{Compressor, Config, IndexWriter, MockIndex, MockIndexWriter, ValueLog};
3+
4+
#[derive(Clone, Default)]
5+
struct NoCompressor;
6+
7+
impl Compressor for NoCompressor {
8+
fn compress(&self, bytes: &[u8]) -> value_log::Result<Vec<u8>> {
9+
Ok(bytes.into())
10+
}
11+
12+
fn decompress(&self, bytes: &[u8]) -> value_log::Result<Vec<u8>> {
13+
Ok(bytes.into())
14+
}
15+
}
16+
17+
#[test]
18+
fn recovery_fail() -> value_log::Result<()> {
19+
let folder = tempfile::tempdir()?;
20+
let vl_path = folder.path();
21+
22+
let index = MockIndex::default();
23+
24+
let items = ["a", "b", "c", "d", "e"];
25+
26+
{
27+
let value_log = ValueLog::open(vl_path, Config::<NoCompressor>::default())?;
28+
29+
for _ in 0..2 {
30+
let mut index_writer = MockIndexWriter(index.clone());
31+
let mut writer = value_log.get_writer()?;
32+
33+
for key in &items {
34+
let value = key.repeat(10_000);
35+
let value = value.as_bytes();
36+
37+
let key = key.as_bytes();
38+
39+
let vhandle = writer.get_next_value_handle();
40+
index_writer.insert_indirect(key, vhandle, value.len() as u32)?;
41+
42+
writer.write(key, value)?;
43+
}
44+
45+
value_log.register_writer(writer)?;
46+
}
47+
48+
{
49+
assert_eq!(2, value_log.segment_count());
50+
}
51+
}
52+
53+
// NOTE: Delete blob file to trigger Unrecoverable (it is referenced in manifest, but not on disk anymore)
54+
std::fs::remove_file(vl_path.join("segments").join("1"))?;
55+
56+
{
57+
matches!(
58+
ValueLog::open(vl_path, Config::<NoCompressor>::default()),
59+
Err(value_log::Error::Unrecoverable),
60+
);
61+
}
62+
63+
Ok(())
64+
}

0 commit comments

Comments
 (0)