Skip to content

Commit e1a98f4

Browse files
committed
add w2d7 Task 2: Block Checksum
1 parent cbb4215 commit e1a98f4

File tree

6 files changed

+94
-6
lines changed

6 files changed

+94
-6
lines changed

Cargo.lock

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

mini-lsm-starter/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ crossbeam-channel = "0.5.11"
1919
serde_json = { version = "1.0" }
2020
serde = { version = "1.0", features = ["derive"] }
2121
farmhash = "1"
22+
crc32fast = "1.4.2"
2223
nom = "7.1.3"
2324
rustyline = "13.0.0"
2425

mini-lsm-starter/src/table.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use std::fs::File;
99
use std::path::Path;
1010
use std::sync::Arc;
1111

12-
use anyhow::{anyhow, Ok, Result};
12+
use anyhow::{anyhow, bail, Ok, Result};
1313
pub use builder::SsTableBuilder;
1414
use bytes::{Buf, BufMut};
1515
pub use iterator::SsTableIterator;
@@ -200,11 +200,17 @@ impl SsTable {
200200
.block_meta
201201
.get(block_idx + 1)
202202
.map_or(self.block_meta_offset, |x| x.offset);
203-
let block_data = self
203+
let block_len = offset_end - offset - 4;
204+
let block_data_chksum = self
204205
.file
205206
.read(offset as u64, (offset_end - offset) as u64)?;
206-
207-
Ok(Arc::new(Block::decode(&block_data[..])))
207+
let block_data = &block_data_chksum[..block_len];
208+
let read_checksum = (&block_data_chksum[block_len..]).get_u32();
209+
let checksum = crc32fast::hash(block_data);
210+
if checksum != read_checksum {
211+
bail!("mismatched block checksum !");
212+
}
213+
Ok(Arc::new(Block::decode(block_data)))
208214
}
209215

210216
/// Read a block from disk, with block cache. (Day 4)

mini-lsm-starter/src/table/builder.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,13 +74,14 @@ impl SsTableBuilder {
7474
// std::mem::replace() is really helpful
7575
let block = std::mem::replace(&mut self.builder, BlockBuilder::new(self.block_size));
7676
let encoded_data = block.build().encode();
77-
// let x = std::mem::take(&mut self.first_key).as_slice();
77+
let check_sum = crc32fast::hash(&encoded_data);
7878
self.meta.push(BlockMeta {
7979
offset: self.data.len(),
8080
first_key: KeyVec::from_vec(std::mem::take(&mut self.first_key)).into_key_bytes(),
8181
last_key: KeyVec::from_vec(std::mem::take(&mut self.last_key)).into_key_bytes(),
8282
});
8383
self.data.extend(encoded_data); //TODO why return a Bytes and extend it to data instead of returning a Vec?
84+
self.data.put_u32(check_sum);
8485
}
8586

8687
/// Get the estimated size of the SSTable.

mini-lsm-starter/src/tests.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,4 @@ mod week2_day2;
1414
mod week2_day3;
1515
mod week2_day4;
1616
mod week2_day5;
17+
mod week2_day6;
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
use tempfile::tempdir;
2+
3+
use crate::{
4+
compact::{
5+
CompactionOptions, LeveledCompactionOptions, SimpleLeveledCompactionOptions,
6+
TieredCompactionOptions,
7+
},
8+
lsm_storage::{LsmStorageOptions, MiniLsm},
9+
tests::harness::dump_files_in_dir,
10+
};
11+
12+
#[test]
13+
fn test_integration_leveled() {
14+
test_integration(CompactionOptions::Leveled(LeveledCompactionOptions {
15+
level_size_multiplier: 2,
16+
level0_file_num_compaction_trigger: 2,
17+
max_levels: 3,
18+
base_level_size_mb: 1,
19+
}))
20+
}
21+
22+
#[test]
23+
fn test_integration_tiered() {
24+
test_integration(CompactionOptions::Tiered(TieredCompactionOptions {
25+
num_tiers: 3,
26+
max_size_amplification_percent: 200,
27+
size_ratio: 1,
28+
min_merge_width: 3,
29+
max_merge_width: None,
30+
}))
31+
}
32+
33+
#[test]
34+
fn test_integration_simple() {
35+
test_integration(CompactionOptions::Simple(SimpleLeveledCompactionOptions {
36+
size_ratio_percent: 200,
37+
level0_file_num_compaction_trigger: 2,
38+
max_levels: 3,
39+
}));
40+
}
41+
42+
fn test_integration(compaction_options: CompactionOptions) {
43+
let dir = tempdir().unwrap();
44+
let mut options = LsmStorageOptions::default_for_week2_test(compaction_options);
45+
options.enable_wal = true;
46+
let storage = MiniLsm::open(&dir, options.clone()).unwrap();
47+
for i in 0..=20 {
48+
storage.put(b"0", format!("v{}", i).as_bytes()).unwrap();
49+
if i % 2 == 0 {
50+
storage.put(b"1", format!("v{}", i).as_bytes()).unwrap();
51+
} else {
52+
storage.delete(b"1").unwrap();
53+
}
54+
if i % 2 == 1 {
55+
storage.put(b"2", format!("v{}", i).as_bytes()).unwrap();
56+
} else {
57+
storage.delete(b"2").unwrap();
58+
}
59+
storage
60+
.inner
61+
.force_freeze_memtable(&storage.inner.state_lock.lock())
62+
.unwrap();
63+
}
64+
storage.close().unwrap();
65+
// ensure some SSTs are not flushed
66+
assert!(
67+
!storage.inner.state.read().memtable.is_empty()
68+
|| !storage.inner.state.read().imm_memtables.is_empty()
69+
);
70+
storage.dump_structure();
71+
drop(storage);
72+
dump_files_in_dir(&dir);
73+
74+
let storage = MiniLsm::open(&dir, options).unwrap();
75+
assert_eq!(&storage.get(b"0").unwrap().unwrap()[..], b"v20".as_slice());
76+
assert_eq!(&storage.get(b"1").unwrap().unwrap()[..], b"v20".as_slice());
77+
assert_eq!(storage.get(b"2").unwrap(), None);
78+
}

0 commit comments

Comments
 (0)