Mercurial > lbo > hg > leveldb-rs
changeset 610:9a561cd122c3
Add CompressorList & Refactor
author | kaiyohugo <41114603+KAIYOHUGO@users.noreply.github.com> |
---|---|
date | Sat, 15 Jul 2023 14:05:55 +0800 |
parents | 68887f0a3e83 |
children | ca88834b15c2 |
files | examples/leveldb-tool/src/main.rs examples/stresstest/src/main.rs src/compressor.rs src/db_impl.rs src/error.rs src/lib.rs src/options.rs src/table_block.rs src/table_builder.rs |
diffstat | 9 files changed, 111 insertions(+), 49 deletions(-) [+] |
line wrap: on
line diff
--- a/examples/leveldb-tool/src/main.rs Tue Jul 04 21:50:32 2023 +0800 +++ b/examples/leveldb-tool/src/main.rs Sat Jul 15 14:05:55 2023 +0800 @@ -1,6 +1,6 @@ extern crate rusty_leveldb; -use rusty_leveldb::{CompressorId, LdbIterator, Options, DB}; +use rusty_leveldb::{compressor, CompressorId, LdbIterator, Options, DB}; use std::env::args; use std::io::{self, Write}; @@ -59,7 +59,7 @@ let mut opt = Options::default(); opt.reuse_logs = false; opt.reuse_manifest = false; - opt.compressor = rusty_leveldb::compressor::SnappyCompressor::ID; + opt.compressor = compressor::SnappyCompressor::ID; let mut db = DB::open("tooldb", opt).unwrap(); match args[1].as_str() {
--- a/examples/stresstest/src/main.rs Tue Jul 04 21:50:32 2023 +0800 +++ b/examples/stresstest/src/main.rs Sat Jul 15 14:05:55 2023 +0800 @@ -12,7 +12,7 @@ fn write(db: &mut DB, n: usize) { time_test::time_test!("write"); - for i in 0..n { + for _ in 0..n { let (k, v) = (gen_string(KEY_LEN), gen_string(VAL_LEN)); db.put(k.as_bytes(), v.as_bytes()).unwrap(); @@ -27,10 +27,10 @@ fn read(db: &mut DB, n: usize) -> usize { let mut succ = 0; time_test::time_test!("read"); - for i in 0..n { + for _ in 0..n { let k = gen_string(KEY_LEN); - if let Some(v) = db.get(k.as_bytes()) { + if let Some(_) = db.get(k.as_bytes()) { succ += 1; } } @@ -38,7 +38,7 @@ } fn main() { - let N = 100_000; + let n = 100_000; let m = 10; let path = "stresstestdb"; let mut entries = 0; @@ -47,11 +47,11 @@ let mut opt = Options::default(); opt.compressor = compressor::SnappyCompressor::ID; let mut db = DB::open(path, opt).unwrap(); - write(&mut db, N); - entries += N; + write(&mut db, n); + entries += n; println!("Wrote {} entries ({}/{})", entries, i + 1, m); - let s = read(&mut db, N); - println!("Read back {} entries (found {}) ({}/{})", N, s, i + 1, m); + let s = read(&mut db, n); + println!("Read back {} entries (found {}) ({}/{})", n, s, i + 1, m); } }
--- a/src/compressor.rs Tue Jul 04 21:50:32 2023 +0800 +++ b/src/compressor.rs Sat Jul 15 14:05:55 2023 +0800 @@ -1,22 +1,46 @@ +/// Custom compression method +/// +/// ``` +/// # use rusty_leveldb::{Compressor, CompressorId}; +/// +/// #[derive(Debug, Clone, Copy, Default)] +/// pub struct CustomCompressor; +/// +/// impl CompressorId for CustomCompressor { +/// const ID: u8 = 0; +/// } +/// +/// impl Compressor for CustomCompressor { +/// fn encode(&self, block: Vec<u8>) -> rusty_leveldb::Result<Vec<u8>> { +/// // Do something +/// Ok(block) +/// } +/// +/// fn decode(&self, block: Vec<u8>) -> rusty_leveldb::Result<Vec<u8>> { +/// // Do something +/// Ok(block) +/// } +/// } +/// ``` +/// +/// See [crate::CompressorList] for usage pub trait Compressor { fn encode(&self, block: Vec<u8>) -> crate::Result<Vec<u8>>; fn decode(&self, block: Vec<u8>) -> crate::Result<Vec<u8>>; } +/// Set default compressor id pub trait CompressorId { const ID: u8; } +/// A compressor that do **Nothing** +/// +/// It default id is `0` #[derive(Debug, Clone, Copy, Default)] pub struct NoneCompressor; -impl NoneCompressor { - pub fn new() -> Box<dyn Compressor> { - Box::new(Self) - } -} - impl CompressorId for NoneCompressor { const ID: u8 = 0; } @@ -31,15 +55,12 @@ } } +/// A compressor that compress data with Google's Snappy +/// +/// It default id is `1` #[derive(Debug, Clone, Copy, Default)] pub struct SnappyCompressor; -impl SnappyCompressor { - pub fn new() -> Box<dyn Compressor> { - Box::new(Self) - } -} - impl CompressorId for SnappyCompressor { const ID: u8 = 1; }
--- a/src/db_impl.rs Tue Jul 04 21:50:32 2023 +0800 +++ b/src/db_impl.rs Sat Jul 15 14:05:55 2023 +0800 @@ -110,9 +110,6 @@ /// depends on the options set (`create_if_missing`, `error_if_exists`). pub fn open<P: AsRef<Path>>(name: P, opt: Options) -> Result<DB> { let name = name.as_ref(); - if opt.compressor_list[opt.compressor as usize].is_none() { - err(StatusCode::InvalidOption, "need set compressor")?; - } let mut db = DB::new(name, opt); let mut ve = VersionEdit::new(); let save_manifest = db.recover(&mut ve)?;
--- a/src/error.rs Tue Jul 04 21:50:32 2023 +0800 +++ b/src/error.rs Sat Jul 15 14:05:55 2023 +0800 @@ -20,7 +20,6 @@ IOError, InvalidArgument, InvalidData, - InvalidOption, LockError, NotFound, NotSupported,
--- a/src/lib.rs Tue Jul 04 21:50:32 2023 +0800 +++ b/src/lib.rs Sat Jul 15 14:05:55 2023 +0800 @@ -87,7 +87,7 @@ pub use error::{Result, Status, StatusCode}; pub use filter::{BloomPolicy, FilterPolicy}; pub use mem_env::MemEnv; -pub use options::{in_memory, Options}; +pub use options::{in_memory, CompressorList, Options}; pub use skipmap::SkipMap; pub use types::LdbIterator; pub use write_batch::WriteBatch;
--- a/src/options.rs Tue Jul 04 21:50:32 2023 +0800 +++ b/src/options.rs Sat Jul 15 14:05:55 2023 +0800 @@ -1,13 +1,13 @@ use crate::block::Block; use crate::cache::Cache; use crate::cmp::{Cmp, DefaultCmp}; -use crate::compressor::Compressor; -use crate::disk_env; +use crate::compressor::{self, Compressor, CompressorId}; use crate::env::Env; -use crate::filter; use crate::infolog::{self, Logger}; use crate::mem_env::MemEnv; use crate::types::{share, Shared}; +use crate::{disk_env, Result}; +use crate::{filter, Status, StatusCode}; use std::default::Default; use std::rc::Rc; @@ -36,11 +36,13 @@ pub block_cache: Shared<Cache<Block>>, pub block_size: usize, pub block_restart_interval: usize, + /// Compressor id in compressor list + /// /// Note: you have to open a database with the same compression type as it was written to, in /// order to not lose data! (this is a bug and will be fixed) pub compressor: u8, - pub compressor_list: Rc<[Option<Box<dyn Compressor>>; 256]>, + pub compressor_list: Rc<CompressorList>, pub reuse_logs: bool, pub reuse_manifest: bool, pub filter_policy: filter::BoxedFilterPolicy, @@ -48,11 +50,6 @@ impl Default for Options { fn default() -> Options { - const INIT: Option<Box<dyn Compressor>> = None; - let mut compressor_list = [INIT; 256]; - compressor_list[0] = Some(crate::compressor::NoneCompressor::new()); - compressor_list[1] = Some(crate::compressor::SnappyCompressor::new()); - Options { cmp: Rc::new(Box::new(DefaultCmp)), env: Rc::new(Box::new(disk_env::PosixDiskEnv::new())), @@ -70,12 +67,64 @@ reuse_logs: true, reuse_manifest: true, compressor: 0, - compressor_list: Rc::new(compressor_list), + compressor_list: Rc::new(CompressorList::default()), filter_policy: Rc::new(Box::new(filter::BloomPolicy::new(DEFAULT_BITS_PER_KEY))), } } } +/// Customize compressor method for leveldb +/// +/// `Default` value is like the code below +/// ``` +/// # use rusty_leveldb::{compressor, CompressorList}; +/// let mut list = CompressorList::new(); +/// list.set(compressor::NoneCompressor); +/// list.set(compressor::SnappyCompressor); +/// ``` +pub struct CompressorList([Option<Box<dyn Compressor>>; 256]); + +impl CompressorList { + /// Create a **Empty** compressor list + pub fn new() -> Self { + const INIT: Option<Box<dyn Compressor>> = None; + Self([INIT; 256]) + } + + /// Set compressor with the id in `CompressorId` trait + pub fn set<T>(&mut self, compressor: T) + where + T: Compressor + CompressorId + 'static, + { + self.set_with_id(T::ID, compressor) + } + + /// Set compressor with id + pub fn set_with_id(&mut self, id: u8, compressor: impl Compressor + 'static) { + self.0[id as usize] = Some(Box::new(compressor)); + } + + pub fn is_set(&self, id: u8) -> bool { + self.0[id as usize].is_some() + } + + pub fn get(&self, id: u8) -> Result<&Box<dyn Compressor + 'static>> { + self.0[id as usize].as_ref().ok_or_else(|| Status { + code: StatusCode::InvalidData, + err: format!("invalid compression id `{}`", id), + }) + } +} + +impl Default for CompressorList { + fn default() -> Self { + let mut list = Self::new(); + list.set(compressor::NoneCompressor); + list.set(compressor::SnappyCompressor); + list + } +} + /// Returns Options that will cause a database to exist purely in-memory instead of being stored on /// disk. This is useful for testing or ephemeral databases. pub fn in_memory() -> Options {
--- a/src/table_block.rs Tue Jul 04 21:50:32 2023 +0800 +++ b/src/table_block.rs Sat Jul 15 14:05:55 2023 +0800 @@ -70,11 +70,11 @@ ); } let compressor_list = opt.compressor_list.clone(); - if let Some(compressor) = compressor_list[compress[0] as usize].as_ref() { - Ok(Block::new(opt, compressor.decode(buf)?)) - } else { - err(StatusCode::InvalidData, "invalid compression type") - } + + Ok(Block::new( + opt, + compressor_list.get(compress[0])?.decode(buf)?, + )) } /// Verify checksum of block
--- a/src/table_builder.rs Tue Jul 04 21:50:32 2023 +0800 +++ b/src/table_builder.rs Sat Jul 15 14:05:55 2023 +0800 @@ -180,9 +180,7 @@ let contents = block.finish(); let compressor_list = self.opt.compressor_list.clone(); - let compressor = compressor_list[self.opt.compressor as usize] - .as_ref() - .unwrap(); + let compressor = compressor_list.get(self.opt.compressor)?; let handle = self.write_block(contents, (self.opt.compressor, compressor))?; @@ -232,9 +230,7 @@ let compressor_list = self.opt.compressor_list.clone(); let compressor_id_pair = ( self.opt.compressor, - compressor_list[self.opt.compressor as usize] - .as_ref() - .unwrap(), + compressor_list.get(self.opt.compressor)?, ); // If there's a pending data block, write it @@ -259,7 +255,7 @@ fblock_data, ( compressor::NoneCompressor::ID, - &compressor::NoneCompressor::new(), + &(Box::new(compressor::NoneCompressor) as Box<dyn Compressor>), ), )?;