Graciously handle backends with no need for resizing, instead of panicking

Signed-off-by: Victor Porof <victor.porof@gmail.com>
without.crypto
Victor Porof 4 years ago
parent a8cef4ee1a
commit 71de0e836d
  1. 18
      src/backend/impl_lmdb/environment.rs
  2. 1
      src/backend/impl_lmdb/error.rs
  3. 7
      src/backend/impl_safe/environment.rs
  4. 2
      src/backend/traits.rs
  5. 19
      src/env.rs
  6. 6
      tests/env-lmdb.rs

@ -13,6 +13,8 @@ use std::{
path::Path,
};
use lmdb::Error as LmdbError;
use super::{
DatabaseFlagsImpl,
DatabaseImpl,
@ -26,6 +28,8 @@ use super::{
use crate::backend::traits::{
BackendEnvironment,
BackendEnvironmentBuilder,
BackendInfo,
BackendStat,
};
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
@ -129,6 +133,20 @@ impl<'e> BackendEnvironment<'e> for EnvironmentImpl {
self.0.freelist().map_err(ErrorImpl::LmdbError)
}
fn load_ratio(&self) -> Result<Option<f32>, Self::Error> {
let stat = self.stat()?;
let info = self.info()?;
let freelist = self.freelist()?;
let last_pgno = info.last_pgno() + 1; // pgno is 0 based.
let total_pgs = info.map_size() / stat.page_size();
if freelist > last_pgno {
return Err(ErrorImpl::LmdbError(LmdbError::Corrupted));
}
let used_pgs = last_pgno - freelist;
Ok(Some(used_pgs as f32 / total_pgs as f32))
}
fn set_map_size(&self, size: usize) -> Result<(), Self::Error> {
self.0.set_map_size(size).map_err(ErrorImpl::LmdbError)
}

@ -41,6 +41,7 @@ impl fmt::Display for ErrorImpl {
impl Into<StoreError> for ErrorImpl {
fn into(self) -> StoreError {
match self {
ErrorImpl::LmdbError(lmdb::Error::Corrupted) => StoreError::DatabaseCorrupted,
ErrorImpl::LmdbError(lmdb::Error::NotFound) => StoreError::KeyValuePairNotFound,
ErrorImpl::LmdbError(lmdb::Error::BadValSize) => StoreError::KeyValuePairBadSize,
ErrorImpl::LmdbError(lmdb::Error::Invalid) => StoreError::FileInvalid,

@ -262,8 +262,13 @@ impl<'e> BackendEnvironment<'e> for EnvironmentImpl {
unimplemented!()
}
fn load_ratio(&self) -> Result<Option<f32>, Self::Error> {
warn!("`load_ratio()` is irrelevant for this storage backend.");
Ok(None)
}
fn set_map_size(&self, size: usize) -> Result<(), Self::Error> {
warn!("Ignoring `set_map_size({})`", size);
warn!("`set_map_size({})` is ignored by this storage backend.", size);
Ok(())
}
}

@ -118,6 +118,8 @@ pub trait BackendEnvironment<'e>: Debug {
fn freelist(&self) -> Result<usize, Self::Error>;
fn load_ratio(&self) -> Result<Option<f32>, Self::Error>;
fn set_map_size(&self, size: usize) -> Result<(), Self::Error>;
}

@ -25,10 +25,8 @@ use crate::{
backend::{
BackendEnvironment,
BackendEnvironmentBuilder,
BackendInfo,
BackendRoCursorTransaction,
BackendRwCursorTransaction,
BackendStat,
SafeModeError,
},
error::StoreError,
@ -282,19 +280,10 @@ where
/// Retrieve the load ratio (# of used pages / total pages) about this environment.
///
/// With the formular: (last_page_no - freelist_pages) / total_pages
pub fn load_ratio(&self) -> Result<f32, StoreError> {
let stat = self.stat()?;
let info = self.info()?;
let freelist = self.env.freelist().map_err(|e| e.into())?;
let last_pgno = info.last_pgno() + 1; // pgno is 0 based.
let total_pgs = info.map_size() / stat.page_size();
if freelist > last_pgno {
return Err(StoreError::DatabaseCorrupted);
}
let used_pgs = last_pgno - freelist;
Ok(used_pgs as f32 / total_pgs as f32)
/// With the formular: (last_page_no - freelist_pages) / total_pages.
/// A value of `None` means that the backend doesn't ever need to be resized.
pub fn load_ratio(&self) -> Result<Option<f32>, StoreError> {
self.env.load_ratio().map_err(|e| e.into())
}
/// Sets the size of the memory map to use for the environment.

@ -753,14 +753,14 @@ fn test_load_ratio() {
let mut writer = k.write().expect("writer");
sk.put(&mut writer, "foo", &Value::Str("bar")).expect("wrote");
writer.commit().expect("commited");
let ratio = k.load_ratio().expect("ratio");
let ratio = k.load_ratio().expect("ratio").unwrap();
assert!(ratio > 0.0_f32 && ratio < 1.0_f32);
// Put data to database should increase the load ratio.
let mut writer = k.write().expect("writer");
sk.put(&mut writer, "bar", &Value::Str(&"more-than-4KB".repeat(1000))).expect("wrote");
writer.commit().expect("commited");
let new_ratio = k.load_ratio().expect("ratio");
let new_ratio = k.load_ratio().expect("ratio").unwrap();
assert!(new_ratio > ratio);
// Clear the database so that all the used pages should go to freelist, hence the ratio
@ -768,7 +768,7 @@ fn test_load_ratio() {
let mut writer = k.write().expect("writer");
sk.clear(&mut writer).expect("clear");
writer.commit().expect("commited");
let after_clear_ratio = k.load_ratio().expect("ratio");
let after_clear_ratio = k.load_ratio().expect("ratio").unwrap();
assert!(after_clear_ratio < new_ratio);
}

Loading…
Cancel
Save