Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove some unwraps in LMDB client #3313

Merged
merged 1 commit into from
May 13, 2020
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 42 additions & 23 deletions store/src/lmdb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use lmdb_zero::LmdbResultExt;

use crate::core::global;
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
pub const ALLOC_CHUNK_SIZE_DEFAULT: usize = 134_217_728; //128 MB
Expand Down Expand Up @@ -102,7 +102,7 @@ impl Store {
fs::create_dir_all(&full_path)
.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)?;

if let Some(max_readers) = max_readers {
Expand All @@ -116,11 +116,7 @@ impl Store {

let env = unsafe { env_builder.open(&full_path, lmdb::open::NOTLS, 0o600)? };

debug!(
"DB Mapsize for {} is {}",
full_path,
env.info().as_ref().unwrap().mapsize
);
debug!("DB Mapsize for {} is {}", full_path, env.info()?.mapsize);
let res = Store {
env: Arc::new(env),
db: Arc::new(RwLock::new(None)),
Expand Down Expand Up @@ -239,29 +235,35 @@ impl Store {
where
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 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)
}

/// Gets a `Readable` value from the db, provided its key. Encapsulates
/// serialization.
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 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>(
&self,
key: &[u8],
access: &lmdb::ConstAccessor<'_>,
db: RwLockReadGuard<'_, Option<Arc<lmdb::Database<'static>>>>,
db: Arc<lmdb::Database<'static>>,
Comment on lines -262 to +264
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this. 👍 Still reviewing though, need to understand what we ware changing here.

) -> 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() {
Ok(Some(mut res)) => match ser::deserialize(&mut res, self.version) {
Ok(res) => Ok(Some(res)),
Expand All @@ -274,19 +276,25 @@ impl Store {

/// Whether the provided key exists
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 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)
}

/// Produces an iterator of (key, value) pairs, where values are `Readable` types
/// moving forward from the provided key.
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 cursor = Arc::new(tx.cursor(db.as_ref().unwrap().clone()).unwrap());
let cursor = Arc::new(tx.cursor(db.clone())?);
Ok(SerIterator {
tx,
cursor,
Expand Down Expand Up @@ -317,10 +325,13 @@ pub struct Batch<'a> {
impl<'a> Batch<'a> {
/// Writes a single key/value pair to the db
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
.access()
.put(&db.as_ref().unwrap(), key, value, lmdb::put::Flags::empty())?;
.put(db, key, value, lmdb::put::Flags::empty())?;
Ok(())
}

Expand Down Expand Up @@ -368,14 +379,22 @@ impl<'a> Batch<'a> {
/// content of the current batch into account.
pub fn get_ser<T: ser::Readable>(&self, key: &[u8]) -> Result<Option<T>, Error> {
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
pub fn delete(&self, key: &[u8]) -> Result<(), Error> {
let db = self.store.db.read();
self.tx.access().del_key(&db.as_ref().unwrap(), key)?;
let lock = self.store.db.read();
let db = lock
.as_ref()
.ok_or_else(|| Error::NotFoundErr("chain db is None".to_string()))?;
self.tx.access().del_key(db, key)?;
Ok(())
}

Expand Down