From 81eb9ce9299b2e31471db3f00457ff3c1a41fb60 Mon Sep 17 00:00:00 2001 From: Determinant Date: Wed, 10 Jun 2020 12:45:25 -0400 Subject: filter out other non-WAL files --- Cargo.lock | 1 + Cargo.toml | 1 + examples/demo1.rs | 6 ++++-- src/wal.rs | 26 +++++++++++++++++++------- 4 files changed, 25 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7b26bbc..34e5a1d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -98,6 +98,7 @@ dependencies = [ "lru", "nix", "rand", + "regex", "scan_fmt", ] diff --git a/Cargo.toml b/Cargo.toml index 1593173..1a60577 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,7 @@ edition = "2018" crc = "1.8.1" lru = "0.5.1" scan_fmt = "0.2.5" +regex = "1" [dev-dependencies] hex = "0.4.2" diff --git a/examples/demo1.rs b/examples/demo1.rs index 104c3b0..e0c7d58 100644 --- a/examples/demo1.rs +++ b/examples/demo1.rs @@ -87,6 +87,8 @@ impl Drop for WALStoreTest { } impl WALStore for WALStoreTest { + type FileNameIter = std::vec::IntoIter; + fn open_file(&self, filename: &str, touch: bool) -> Option> { println!("open_file(filename={}, touch={})", filename, touch); let filename = filename.to_string(); @@ -98,13 +100,13 @@ impl WALStore for WALStoreTest { unlinkat(Some(self.rootfd), filename, UnlinkatFlags::NoRemoveDir).or_else(|_| Err(())) } - fn enumerate_files(&self) -> Box<[String]> { + fn enumerate_files(&self) -> Self::FileNameIter { println!("enumerate_files()"); let mut logfiles = Vec::new(); for fname in std::fs::read_dir(&self.rootpath).unwrap() { logfiles.push(fname.unwrap().file_name().into_string().unwrap()) } - logfiles.into_boxed_slice() + logfiles.into_iter() } fn apply_payload(&self, payload: WALBytes) { diff --git a/src/wal.rs b/src/wal.rs index 05ffd01..0ba35fb 100644 --- a/src/wal.rs +++ b/src/wal.rs @@ -55,20 +55,29 @@ pub trait WALFile { fn allocate(&self, offset: WALPos, length: usize) -> Result<(), ()>; /// Truncate a file to a specified length. fn truncate(&self, length: usize) -> Result<(), ()>; - /// Write data with offset. + /// Write data with offset. We assume the actual writes on the storage medium are _strictly + /// ordered_ the same way as this callback is invoked. We also assume all previous + /// `allocate/truncate` invocation should be visible if ordered earlier (should be guaranteed + /// by most OS). Additionally, the final write caused by each invocation of this function + /// should be _atomic_ (the entire single write should be all or nothing). fn write(&self, offset: WALPos, data: WALBytes); /// Read data with offset. fn read(&self, offset: WALPos, length: usize) -> WALBytes; } pub trait WALStore { + type FileNameIter: Iterator; + /// Open a file given the filename, create the file if not exists when `touch` is `true`. fn open_file(&self, filename: &str, touch: bool) -> Option>; /// Unlink a file given the filename. fn remove_file(&self, filename: &str) -> Result<(), ()>; - /// Enumerate all WAL files. - fn enumerate_files(&self) -> Box<[String]>; - /// Apply (redo) the payload during recovery. + /// Enumerate all WAL filenames. It should include all WAL files that are previously opened + /// (created) but not removed. The list could be unordered. + fn enumerate_files(&self) -> Self::FileNameIter; + /// Apply the payload during recovery. This notifies the application should redo the given + /// operation to ensure its state is consistent (the major goal of having a WAL). We assume + /// the application applies the payload by the _order_ of this callback invocation. fn apply_payload(&self, payload: WALBytes); } @@ -282,19 +291,22 @@ impl WALWriter { pub struct WALLoader { file_pool: WALFilePool, + filename_fmt: regex::Regex } impl WALLoader { pub fn new(store: F, file_nbit: u8, block_nbit: u8, cache_size: usize) -> Self { let file_pool = WALFilePool::new(store, file_nbit, block_nbit, cache_size); - WALLoader{ file_pool } + let filename_fmt = regex::Regex::new(r"[0-9a-f]+\.log").unwrap(); + WALLoader{ file_pool, filename_fmt } } pub fn recover(mut self) -> WALWriter { let block_size = 1 << self.file_pool.block_nbit; let msize = std::mem::size_of::() as u32; - let mut logfiles = self.file_pool.store.enumerate_files(); - // TODO: use regex to filter out invalid files + let mut logfiles: Vec = self.file_pool.store + .enumerate_files() + .filter(|f| self.filename_fmt.is_match(f)).collect(); // TODO: check for missing logfiles logfiles.sort(); let mut chunks = None; -- cgit v1.2.3