Skip to content

Commit

Permalink
expose static Manager singleton to consumers
Browse files Browse the repository at this point in the history
  • Loading branch information
mykmelez committed May 16, 2018
1 parent 44960a3 commit 273ff58
Show file tree
Hide file tree
Showing 4 changed files with 20 additions and 16 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ backtrace = ["failure/backtrace", "failure/std"]
[dependencies]
arrayref = "0.3"
bincode = "0.9"
lazy_static = "1.0"
lmdb = "0.7"
ordered-float = "0.5"
uuid = "0.5"
Expand Down
3 changes: 2 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

#[macro_use] extern crate arrayref;
#[macro_use] extern crate failure;
#[macro_use] extern crate lazy_static;

extern crate bincode;
extern crate lmdb;
Expand Down Expand Up @@ -48,7 +49,7 @@ pub use integer::{
};

pub use manager::{
Manager,
MANAGER,
};

pub use readwrite::{
Expand Down
18 changes: 11 additions & 7 deletions src/manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ use std::path::{

use std::sync::{
Arc,
Mutex,
RwLock,
};

Expand All @@ -35,31 +34,36 @@ use ::Rkv;

/// A process is only permitted to have one open handle to each database. This manager
/// exists to enforce that constraint: don't open databases directly.
lazy_static! {
pub static ref MANAGER: RwLock<Manager> = {
RwLock::new(Manager::new())
};
}

pub struct Manager {
stores: Mutex<BTreeMap<PathBuf, Arc<RwLock<Rkv>>>>,
stores: BTreeMap<PathBuf, Arc<RwLock<Rkv>>>,
}

impl Manager {
pub fn new() -> Manager {
fn new() -> Manager {
Manager {
stores: Mutex::new(Default::default()),
stores: Default::default(),
}
}

/// Return the open store at `path`, returning `None` if it has not already been opened.
pub fn get<'p, P>(&self, path: P) -> Result<Option<Arc<RwLock<Rkv>>>, ::std::io::Error>
where P: Into<&'p Path> {
let canonical = path.into().canonicalize()?;
Ok(self.stores.lock().unwrap().get(&canonical).cloned())
Ok(self.stores.get(&canonical).cloned())
}

/// Return the open store at `path`, or create it by calling `f`.
pub fn get_or_create<'p, F, P>(&mut self, path: P, f: F) -> Result<Arc<RwLock<Rkv>>, StoreError>
where F: FnOnce(&Path) -> Result<Rkv, StoreError>,
P: Into<&'p Path> {
let canonical = path.into().canonicalize()?;
let mut map = self.stores.lock().unwrap();
Ok(match map.entry(canonical) {
Ok(match self.stores.entry(canonical) {
Entry::Occupied(e) => e.get().clone(),
Entry::Vacant(e) => {
let k = Arc::new(RwLock::new(f(e.key().as_path())?));
Expand Down
14 changes: 6 additions & 8 deletions tests/manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ extern crate rkv;
extern crate tempdir;

use rkv::{
Manager,
MANAGER,
Rkv,
};

Expand All @@ -16,17 +16,15 @@ use std::sync::{

#[test]
// Identical to the same-named unit test, but this one confirms that it works
// via public Manager APIs.
// via the public MANAGER singleton.
fn test_same() {
let root = TempDir::new("test_same").expect("tempdir");
let root = TempDir::new("test_same_singleton").expect("tempdir");
fs::create_dir_all(root.path()).expect("dir created");

let mut manager = Manager::new();

let p = root.path();
assert!(manager.get(p).expect("success").is_none());
assert!(MANAGER.read().unwrap().get(p).expect("success").is_none());

let created_arc = manager.get_or_create(p, Rkv::new).expect("created");
let fetched_arc = manager.get(p).expect("success").expect("existed");
let created_arc = MANAGER.write().unwrap().get_or_create(p, Rkv::new).expect("created");
let fetched_arc = MANAGER.read().unwrap().get(p).expect("success").expect("existed");
assert!(Arc::ptr_eq(&created_arc, &fetched_arc));
}

0 comments on commit 273ff58

Please sign in to comment.