Remove some unwraps in LMDB client (#3313)

This commit is contained in:
hashmap 2020-05-13 16:18:55 +02:00 committed by GitHub
parent e826cd82f9
commit 2c62111561
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -24,7 +24,7 @@ use lmdb_zero::LmdbResultExt;
use crate::core::global; use crate::core::global;
use crate::core::ser::{self, ProtocolVersion}; use crate::core::ser::{self, ProtocolVersion};
use crate::util::{RwLock, RwLockReadGuard}; use crate::util::RwLock;
/// number of bytes to grow the database by when needed /// number of bytes to grow the database by when needed
pub const ALLOC_CHUNK_SIZE_DEFAULT: usize = 134_217_728; //128 MB pub const ALLOC_CHUNK_SIZE_DEFAULT: usize = 134_217_728; //128 MB
@ -102,7 +102,7 @@ impl Store {
fs::create_dir_all(&full_path) fs::create_dir_all(&full_path)
.expect("Unable to create directory 'db_root' to store chain_data"); .expect("Unable to create directory 'db_root' to store chain_data");
let mut env_builder = lmdb::EnvBuilder::new().unwrap(); let mut env_builder = lmdb::EnvBuilder::new()?;
env_builder.set_maxdbs(8)?; env_builder.set_maxdbs(8)?;
if let Some(max_readers) = max_readers { if let Some(max_readers) = max_readers {
@ -116,11 +116,7 @@ impl Store {
let env = unsafe { env_builder.open(&full_path, lmdb::open::NOTLS, 0o600)? }; let env = unsafe { env_builder.open(&full_path, lmdb::open::NOTLS, 0o600)? };
debug!( debug!("DB Mapsize for {} is {}", full_path, env.info()?.mapsize);
"DB Mapsize for {} is {}",
full_path,
env.info().as_ref().unwrap().mapsize
);
let res = Store { let res = Store {
env: Arc::new(env), env: Arc::new(env),
db: Arc::new(RwLock::new(None)), db: Arc::new(RwLock::new(None)),
@ -239,29 +235,35 @@ impl Store {
where where
F: Fn(&[u8]) -> T, F: Fn(&[u8]) -> T,
{ {
let db = self.db.read(); let lock = self.db.read();
let db = lock
.as_ref()
.ok_or_else(|| Error::NotFoundErr("chain db is None".to_string()))?;
let txn = lmdb::ReadTransaction::new(self.env.clone())?; let txn = lmdb::ReadTransaction::new(self.env.clone())?;
let access = txn.access(); let access = txn.access();
let res = access.get(&db.as_ref().unwrap(), key); let res = access.get(db, key);
res.map(f).to_opt().map_err(From::from) res.map(f).to_opt().map_err(From::from)
} }
/// Gets a `Readable` value from the db, provided its key. Encapsulates /// Gets a `Readable` value from the db, provided its key. Encapsulates
/// serialization. /// serialization.
pub fn get_ser<T: ser::Readable>(&self, key: &[u8]) -> Result<Option<T>, Error> { pub fn get_ser<T: ser::Readable>(&self, key: &[u8]) -> Result<Option<T>, Error> {
let db = self.db.read(); let lock = self.db.read();
let db = lock
.as_ref()
.ok_or_else(|| Error::NotFoundErr("chain db is None".to_string()))?;
let txn = lmdb::ReadTransaction::new(self.env.clone())?; let txn = lmdb::ReadTransaction::new(self.env.clone())?;
let access = txn.access(); let access = txn.access();
self.get_ser_access(key, &access, db) self.get_ser_access(key, &access, db.clone())
} }
fn get_ser_access<T: ser::Readable>( fn get_ser_access<T: ser::Readable>(
&self, &self,
key: &[u8], key: &[u8],
access: &lmdb::ConstAccessor<'_>, access: &lmdb::ConstAccessor<'_>,
db: RwLockReadGuard<'_, Option<Arc<lmdb::Database<'static>>>>, db: Arc<lmdb::Database<'static>>,
) -> Result<Option<T>, Error> { ) -> Result<Option<T>, Error> {
let res: lmdb::error::Result<&[u8]> = access.get(&db.as_ref().unwrap(), key); let res: lmdb::error::Result<&[u8]> = access.get(&db, key);
match res.to_opt() { match res.to_opt() {
Ok(Some(mut res)) => match ser::deserialize(&mut res, self.version) { Ok(Some(mut res)) => match ser::deserialize(&mut res, self.version) {
Ok(res) => Ok(Some(res)), Ok(res) => Ok(Some(res)),
@ -274,19 +276,25 @@ impl Store {
/// Whether the provided key exists /// Whether the provided key exists
pub fn exists(&self, key: &[u8]) -> Result<bool, Error> { pub fn exists(&self, key: &[u8]) -> Result<bool, Error> {
let db = self.db.read(); let lock = self.db.read();
let db = lock
.as_ref()
.ok_or_else(|| Error::NotFoundErr("chain db is None".to_string()))?;
let txn = lmdb::ReadTransaction::new(self.env.clone())?; let txn = lmdb::ReadTransaction::new(self.env.clone())?;
let access = txn.access(); let access = txn.access();
let res: lmdb::error::Result<&lmdb::Ignore> = access.get(&db.as_ref().unwrap(), key); let res: lmdb::error::Result<&lmdb::Ignore> = access.get(db, key);
res.to_opt().map(|r| r.is_some()).map_err(From::from) res.to_opt().map(|r| r.is_some()).map_err(From::from)
} }
/// Produces an iterator of (key, value) pairs, where values are `Readable` types /// Produces an iterator of (key, value) pairs, where values are `Readable` types
/// moving forward from the provided key. /// moving forward from the provided key.
pub fn iter<T: ser::Readable>(&self, from: &[u8]) -> Result<SerIterator<T>, Error> { pub fn iter<T: ser::Readable>(&self, from: &[u8]) -> Result<SerIterator<T>, Error> {
let db = self.db.read(); let lock = self.db.read();
let db = lock
.as_ref()
.ok_or_else(|| Error::NotFoundErr("chain db is None".to_string()))?;
let tx = Arc::new(lmdb::ReadTransaction::new(self.env.clone())?); let tx = Arc::new(lmdb::ReadTransaction::new(self.env.clone())?);
let cursor = Arc::new(tx.cursor(db.as_ref().unwrap().clone()).unwrap()); let cursor = Arc::new(tx.cursor(db.clone())?);
Ok(SerIterator { Ok(SerIterator {
tx, tx,
cursor, cursor,
@ -317,10 +325,13 @@ pub struct Batch<'a> {
impl<'a> Batch<'a> { impl<'a> Batch<'a> {
/// Writes a single key/value pair to the db /// Writes a single key/value pair to the db
pub fn put(&self, key: &[u8], value: &[u8]) -> Result<(), Error> { pub fn put(&self, key: &[u8], value: &[u8]) -> Result<(), Error> {
let db = self.store.db.read(); let lock = self.store.db.read();
let db = lock
.as_ref()
.ok_or_else(|| Error::NotFoundErr("chain db is None".to_string()))?;
self.tx self.tx
.access() .access()
.put(&db.as_ref().unwrap(), key, value, lmdb::put::Flags::empty())?; .put(db, key, value, lmdb::put::Flags::empty())?;
Ok(()) Ok(())
} }
@ -368,14 +379,22 @@ impl<'a> Batch<'a> {
/// content of the current batch into account. /// content of the current batch into account.
pub fn get_ser<T: ser::Readable>(&self, key: &[u8]) -> Result<Option<T>, Error> { pub fn get_ser<T: ser::Readable>(&self, key: &[u8]) -> Result<Option<T>, Error> {
let access = self.tx.access(); let access = self.tx.access();
let db = self.store.db.read();
self.store.get_ser_access(key, &access, db) let lock = self.store.db.read();
let db = lock
.as_ref()
.ok_or_else(|| Error::NotFoundErr("chain db is None".to_string()))?;
self.store.get_ser_access(key, &access, db.clone())
} }
/// Deletes a key/value pair from the db /// Deletes a key/value pair from the db
pub fn delete(&self, key: &[u8]) -> Result<(), Error> { pub fn delete(&self, key: &[u8]) -> Result<(), Error> {
let db = self.store.db.read(); let lock = self.store.db.read();
self.tx.access().del_key(&db.as_ref().unwrap(), key)?; let db = lock
.as_ref()
.ok_or_else(|| Error::NotFoundErr("chain db is None".to_string()))?;
self.tx.access().del_key(db, key)?;
Ok(()) Ok(())
} }