use super::*; use crate::forwards_iter::SimpleForwardsBlockRootsIterator; use crate::impls::beacon_state::{get_full_state, store_full_state}; use crate::metrics; 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 std::marker::PhantomData; use std::path::Path; /// A wrapped leveldb database. pub struct LevelDB { db: Database, _phantom: PhantomData, } impl LevelDB { /// Open a database at `path`, creating a new database if one does not already exist. 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, _phantom: PhantomData, }) } 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 } } } /// Used for keying leveldb. 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 { type ForwardsBlockRootsIterator = SimpleForwardsBlockRootsIterator; /// Retrieve some bytes in `column` with `key`. fn get_bytes(&self, col: &str, key: &[u8]) -> Result>, Error> { let column_key = Self::get_key_for_col(col, key); metrics::inc_counter(&metrics::DISK_DB_READ_COUNT); let timer = metrics::start_timer(&metrics::DISK_DB_READ_TIMES); self.db .get(self.read_options(), column_key) .map_err(Into::into) .map(|opt| { opt.map(|bytes| { metrics::inc_counter_by(&metrics::DISK_DB_READ_BYTES, bytes.len() as i64); metrics::stop_timer(timer); bytes }) }) } /// Store some `value` in `column`, indexed with `key`. fn put_bytes(&self, col: &str, key: &[u8], val: &[u8]) -> Result<(), Error> { let column_key = Self::get_key_for_col(col, key); metrics::inc_counter(&metrics::DISK_DB_WRITE_COUNT); metrics::inc_counter_by(&metrics::DISK_DB_WRITE_BYTES, val.len() as i64); let timer = metrics::start_timer(&metrics::DISK_DB_WRITE_TIMES); self.db .put(self.write_options(), column_key, val) .map_err(Into::into) .map(|()| { metrics::stop_timer(timer); }) } /// Return `true` if `key` exists in `column`. fn key_exists(&self, col: &str, key: &[u8]) -> Result { let column_key = Self::get_key_for_col(col, key); metrics::inc_counter(&metrics::DISK_DB_EXISTS_COUNT); self.db .get(self.read_options(), column_key) .map_err(Into::into) .and_then(|val| Ok(val.is_some())) } /// Removes `key` from `column`. fn key_delete(&self, col: &str, key: &[u8]) -> Result<(), Error> { let column_key = Self::get_key_for_col(col, key); metrics::inc_counter(&metrics::DISK_DB_DELETE_COUNT); self.db .delete(self.write_options(), column_key) .map_err(Into::into) } /// Store a state in the store. fn put_state(&self, state_root: &Hash256, state: &BeaconState) -> Result<(), Error> { store_full_state(self, state_root, &state) } /// Fetch a state from the store. fn get_state( &self, state_root: &Hash256, _: Option, ) -> Result>, Error> { get_full_state(self, state_root) } fn forwards_block_roots_iterator( store: Arc, start_slot: Slot, end_state: BeaconState, end_block_root: Hash256, _: &ChainSpec, ) -> Self::ForwardsBlockRootsIterator { SimpleForwardsBlockRootsIterator::new(store, start_slot, end_state, end_block_root) } } impl From for Error { fn from(e: LevelDBError) -> Error { Error::DBError { message: format!("{:?}", e), } } }