From 7d067926dd20beb1f2df314d35e33274fbfc1e97 Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Tue, 21 May 2019 16:29:34 +1000 Subject: [PATCH] Replace RocksDB with LevelDB --- beacon_node/db/Cargo.toml | 6 +- beacon_node/db/src/leveldb_store.rs | 100 ++++++++++++++++++++++++++++ beacon_node/db/src/lib.rs | 20 ++++++ 3 files changed, 125 insertions(+), 1 deletion(-) create mode 100644 beacon_node/db/src/leveldb_store.rs diff --git a/beacon_node/db/Cargo.toml b/beacon_node/db/Cargo.toml index b6cdafe04..808d420a5 100644 --- a/beacon_node/db/Cargo.toml +++ b/beacon_node/db/Cargo.toml @@ -4,12 +4,16 @@ version = "0.1.0" authors = ["Paul Hauner "] edition = "2018" +[dev-dependencies] +tempfile = "3" + [dependencies] blake2-rfc = "0.2.18" bls = { path = "../../eth2/utils/bls" } bytes = "0.4.10" +db-key = "0.0.5" +leveldb = "0.8.4" parking_lot = "0.7" -rocksdb = "0.10.1" ssz = { path = "../../eth2/utils/ssz" } ssz_derive = { path = "../../eth2/utils/ssz_derive" } tree_hash = { path = "../../eth2/utils/tree_hash" } diff --git a/beacon_node/db/src/leveldb_store.rs b/beacon_node/db/src/leveldb_store.rs new file mode 100644 index 000000000..c60e34283 --- /dev/null +++ b/beacon_node/db/src/leveldb_store.rs @@ -0,0 +1,100 @@ +use super::*; +use db_key::Key; +use leveldb::database::kv::KV; +use leveldb::database::Database; +use leveldb::error::Error as LevelDBError; +use leveldb::options::{Options, ReadOptions, WriteOptions}; +use parking_lot::RwLock; +use std::path::Path; + +pub struct LevelDB { + db: RwLock>, +} + +impl LevelDB { + pub fn open(path: &Path) -> Result { + let mut options = Options::new(); + + options.create_if_missing = true; + + let db = Database::open(path, options)?; + + Ok(Self { + db: RwLock::new(db), + }) + } + + fn read_options(&self) -> ReadOptions { + ReadOptions::new() + } + + fn write_options(&self) -> WriteOptions { + WriteOptions::new() + } + + fn get_key_for_col(col: &str, key: &[u8]) -> BytesKey { + let mut col = col.as_bytes().to_vec(); + col.append(&mut key.to_vec()); + BytesKey { key: col } + } +} + +pub struct BytesKey { + key: Vec, +} + +impl Key for BytesKey { + fn from_u8(key: &[u8]) -> Self { + Self { key: key.to_vec() } + } + + fn as_slice T>(&self, f: F) -> T { + f(self.key.as_slice()) + } +} + +impl Store for LevelDB { + fn get_bytes(&self, col: &str, key: &[u8]) -> Result, Error> { + let column_key = Self::get_key_for_col(col, key); + + self.db + .read() + .get(self.read_options(), column_key) + .map_err(Into::into) + } + + fn put_bytes(&self, col: &str, key: &[u8], val: &[u8]) -> Result<(), Error> { + let column_key = Self::get_key_for_col(col, key); + + self.db + .write() + .put(self.write_options(), column_key, val) + .map_err(Into::into) + } + + fn key_exists(&self, col: &str, key: &[u8]) -> Result { + let column_key = Self::get_key_for_col(col, key); + + self.db + .read() + .get(self.read_options(), column_key) + .map_err(Into::into) + .and_then(|val| Ok(val.is_some())) + } + + fn key_delete(&self, col: &str, key: &[u8]) -> Result<(), Error> { + let column_key = Self::get_key_for_col(col, key); + self.db + .write() + .delete(self.write_options(), column_key) + .map_err(Into::into) + } +} + +impl From for Error { + fn from(e: LevelDBError) -> Error { + Error::DBError { + message: format!("{:?}", e), + } + } +} diff --git a/beacon_node/db/src/lib.rs b/beacon_node/db/src/lib.rs index 21b5b0a75..d31dc06b0 100644 --- a/beacon_node/db/src/lib.rs +++ b/beacon_node/db/src/lib.rs @@ -2,8 +2,10 @@ mod block_at_slot; mod errors; mod impls; +mod leveldb_store; mod memory_db; +pub use self::leveldb_store::LevelDB; pub use self::memory_db::MemoryDB; pub use errors::Error; pub use types::*; @@ -106,6 +108,7 @@ mod tests { use super::*; use ssz::{Decode, Encode}; use ssz_derive::{Decode, Encode}; + use tempfile::tempdir; #[derive(PartialEq, Debug, Encode, Decode)] struct StorableThing { @@ -127,6 +130,23 @@ mod tests { } } + #[test] + fn leveldb_can_store_and_retrieve() { + let dir = tempdir().unwrap(); + let path = dir.path(); + + let store = LevelDB::open(&path).unwrap(); + + let key = Hash256::random(); + let item = StorableThing { a: 1, b: 42 }; + + store.put(&key, &item).unwrap(); + + let retrieved = store.get(&key).unwrap().unwrap(); + + assert_eq!(item, retrieved); + } + #[test] fn memorydb_can_store_and_retrieve() { let store = MemoryDB::open();