diff --git a/mini-lsm-book/src/00-get-started.md b/mini-lsm-book/src/00-get-started.md index d1603bf..82f2ec1 100644 --- a/mini-lsm-book/src/00-get-started.md +++ b/mini-lsm-book/src/00-get-started.md @@ -28,7 +28,7 @@ cargo x install-tools ## Run tests ``` -cargo x copy-test day1 +cargo x copy-test --week 1 --day 1 cargo x scheck ``` diff --git a/mini-lsm-book/src/week1-01-memtable.md b/mini-lsm-book/src/week1-01-memtable.md index 67fb481..32f6c7d 100644 --- a/mini-lsm-book/src/week1-01-memtable.md +++ b/mini-lsm-book/src/week1-01-memtable.md @@ -8,6 +8,13 @@ In this chapter, you will: * Implement freezing memtable logic. * Implement LSM read path `get` for memtables. +To copy the test cases into the starter code and run them, + +``` +cargo x copy-test --week 1 --day 1 +cargo x scheck +``` + ## Task 1: SkipList Memtable In this task, you will need to modify: diff --git a/mini-lsm-book/src/week1-02-merge-iterator.md b/mini-lsm-book/src/week1-02-merge-iterator.md index 428e49d..48714ad 100644 --- a/mini-lsm-book/src/week1-02-merge-iterator.md +++ b/mini-lsm-book/src/week1-02-merge-iterator.md @@ -8,6 +8,14 @@ In this chapter, you will: * Implement merge iterator. * Implement LSM read path `scan` for memtables. + +To copy the test cases into the starter code and run them, + +``` +cargo x copy-test --week 1 --day 2 +cargo x scheck +``` + ## Task 1: Memtable Iterator In this chapter, we will implement the LSM `scan` interface. `scan` returns a range of key-value pairs in order using an iterator API. In the previous chapter, you have implemented the `get` API and the logic to create immutable memtables, and your LSM state should now have multiple memtables. You will need to first create iterators on a single memtable, then create a merge iterator on all memtables, and finally implement the range limit for the iterators. diff --git a/mini-lsm-book/src/week1-03-block.md b/mini-lsm-book/src/week1-03-block.md index 3e81d01..087e66c 100644 --- a/mini-lsm-book/src/week1-03-block.md +++ b/mini-lsm-book/src/week1-03-block.md @@ -7,6 +7,14 @@ In this chapter, you will: * Implement SST block encoding. * Implement SST block decoding and block iterator. + +To copy the test cases into the starter code and run them, + +``` +cargo x copy-test --week 1 --day 3 +cargo x scheck +``` + ## Task 1: Block Builder You have already implemented all in-memory structures for an LSM storage engine in the previous two chapters. Now it's time to build the on-disk structures. The basic unit of the on-disk structure is blocks. Blocks are usually of 4-KB size (the size may vary depending on the storage medium), which is equivalent to the page size in the operating system and the page size on an SSD. A block stores ordered key-value pairs. An SST is composed of multiple blocks. When the number of memtables exceed the system limit, it will flush the memtable as an SST. In this chapter, you will implement the encoding and decoding of a block. diff --git a/mini-lsm-book/src/week1-04-sst.md b/mini-lsm-book/src/week1-04-sst.md index 693c14f..90a03c5 100644 --- a/mini-lsm-book/src/week1-04-sst.md +++ b/mini-lsm-book/src/week1-04-sst.md @@ -7,6 +7,14 @@ In this chapter, you will: * Implement SST encoding and metadata encoding. * Implement SST decoding and iterator. + +To copy the test cases into the starter code and run them, + +``` +cargo x copy-test --week 1 --day 4 +cargo x scheck +``` + ## Task 1: SST Builder In this task, you will need to modify: diff --git a/mini-lsm-book/src/week1-05-read-path.md b/mini-lsm-book/src/week1-05-read-path.md index a771f5d..99e9206 100644 --- a/mini-lsm-book/src/week1-05-read-path.md +++ b/mini-lsm-book/src/week1-05-read-path.md @@ -8,6 +8,14 @@ In this chapter, you will: * Implement LSM read path `get` with SSTs. * Implement LSM read path `scan` with SSTs. + +To copy the test cases into the starter code and run them, + +``` +cargo x copy-test --week 1 --day 5 +cargo x scheck +``` + ## Task 1: Two Merge Iterator ## Task 2: Read Path - Get diff --git a/mini-lsm-book/src/week1-06-write-path.md b/mini-lsm-book/src/week1-06-write-path.md index 202344e..f42ab0d 100644 --- a/mini-lsm-book/src/week1-06-write-path.md +++ b/mini-lsm-book/src/week1-06-write-path.md @@ -7,6 +7,14 @@ In this chapter, you will: * Implement the LSM write path with L0 flush. * Implement the logic to correctly update the LSM state. + +To copy the test cases into the starter code and run them, + +``` +cargo x copy-test --week 1 --day 6 +cargo x scheck +``` + ## Task 1: Flush Memtable to SST ## Task 2: Update the LSM State diff --git a/mini-lsm-book/src/week1-07-sst-optimizations.md b/mini-lsm-book/src/week1-07-sst-optimizations.md index 30bf631..91f637e 100644 --- a/mini-lsm-book/src/week1-07-sst-optimizations.md +++ b/mini-lsm-book/src/week1-07-sst-optimizations.md @@ -9,6 +9,14 @@ In this chapter, you will: * Implement bloom filter on SSTs and integrate into the LSM read path `get`. * Implement key compression in SST block format. + +To copy the test cases into the starter code and run them, + +``` +cargo x copy-test --week 1 --day 7 +cargo x scheck +``` + ## Task 1: Bloom Filters ## Task 2: Integrate Bloom Filter on the Read Path diff --git a/mini-lsm/src/tests/day1.rs b/mini-lsm/src/tests/week1_day1.rs similarity index 100% rename from mini-lsm/src/tests/day1.rs rename to mini-lsm/src/tests/week1_day1.rs diff --git a/mini-lsm/src/tests/day2.rs b/mini-lsm/src/tests/week1_day2.rs similarity index 100% rename from mini-lsm/src/tests/day2.rs rename to mini-lsm/src/tests/week1_day2.rs diff --git a/mini-lsm/src/tests/day3.rs b/mini-lsm/src/tests/week1_day3.rs similarity index 100% rename from mini-lsm/src/tests/day3.rs rename to mini-lsm/src/tests/week1_day3.rs diff --git a/mini-lsm/src/tests/day4.rs b/mini-lsm/src/tests/week1_day4.rs similarity index 100% rename from mini-lsm/src/tests/day4.rs rename to mini-lsm/src/tests/week1_day4.rs diff --git a/xtask/src/main.rs b/xtask/src/main.rs index 1194976..2cbb711 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -1,16 +1,16 @@ -use std::path::PathBuf; +use std::path::{Path, PathBuf}; use anyhow::{anyhow, Result}; use clap::Parser; use console::style; use duct::cmd; -#[derive(clap::Subcommand, Debug)] -enum CopyTestAction { - Day1, - Day2, - Day3, - Day4, +#[derive(clap::Parser, Debug)] +struct CopyTestAction { + #[arg(long)] + week: usize, + #[arg(long)] + day: usize, } #[derive(clap::Subcommand, Debug)] @@ -30,7 +30,6 @@ enum Action { /// Check starter code Scheck, /// Copy test cases - #[command(subcommand)] CopyTest(CopyTestAction), } @@ -126,58 +125,44 @@ fn sync() -> Result<()> { } fn copy_test_case(test: CopyTestAction) -> Result<()> { - match test { - CopyTestAction::Day1 => { - cmd!( - "cp", - "mini-lsm/src/block/tests.rs", - "mini-lsm-starter/src/block/tests.rs" - ) - .run()?; - } - CopyTestAction::Day2 => { - cmd!( - "cp", - "mini-lsm/src/table/tests.rs", - "mini-lsm-starter/src/table/tests.rs" - ) - .run()?; - } - CopyTestAction::Day3 => { - cmd!( - "cp", - "mini-lsm/src/mem_table/tests.rs", - "mini-lsm-starter/src/mem_table/tests.rs" - ) - .run()?; - cmd!( - "cp", - "mini-lsm/src/iterators/tests/merge_iterator_test.rs", - "mini-lsm-starter/src/iterators/tests/merge_iterator_test.rs" - ) - .run()?; - cmd!( - "cp", - "mini-lsm/src/iterators/tests/two_merge_iterator_test.rs", - "mini-lsm-starter/src/iterators/tests/two_merge_iterator_test.rs" - ) - .run()?; - cmd!( - "cp", - "mini-lsm/src/iterators/tests.rs", - "mini-lsm-starter/src/iterators/tests.rs" - ) - .run()?; - } - CopyTestAction::Day4 => { - cmd!( - "cp", - "mini-lsm/src/tests/day4_tests.rs", - "mini-lsm-starter/src/tests/day4_tests.rs" - ) - .run()?; + use std::fmt::Write; + let src_dir = "mini-lsm/src/tests"; + let target_dir = "mini-lsm-starter/src/tests"; + if !Path::new(target_dir).exists() { + std::fs::create_dir(target_dir)?; + } + let test_filename = format!("week{}_day{}.rs", test.week, test.day); + let src = format!("{}/{}", src_dir, test_filename); + let target = format!("{}/{}", target_dir, test_filename); + cmd!("cp", src, target).run()?; + let test_filename = "harness.rs"; + let src = format!("{}/{}", src_dir, test_filename); + let target = format!("{}/{}", target_dir, test_filename); + cmd!("cp", src, target).run()?; + let mut test_file = Vec::new(); + for file in Path::new(&target_dir).read_dir()? { + let file = file?; + let fname = file.file_name(); + let fnamestr = fname + .as_os_str() + .to_str() + .ok_or_else(|| anyhow!("invalid filename?"))?; + if let Some((mod_name, _)) = fnamestr.split_once(".rs") { + test_file.push(mod_name.to_string()); } } + let mut tests_mod = String::new(); + writeln!(tests_mod, "//! DO NOT MODIFY -- Mini-LSM tests modules")?; + writeln!( + tests_mod, + "//! This file will be automatically rewritten by the copy-test command." + )?; + writeln!(tests_mod)?; + for tf in test_file { + writeln!(tests_mod, "mod {};", tf)?; + } + println!("{}", tests_mod); + std::fs::write("mini-lsm-starter/src/tests.rs", tests_mod)?; Ok(()) }