Only lifetime issues with thread_local remaining
This commit is contained in:
parent
baa7cb4f8f
commit
9e6d6c2834
1 changed files with 44 additions and 35 deletions
|
@ -10,6 +10,7 @@
|
||||||
|
|
||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
|
|
||||||
|
use std::cell::RefCell;
|
||||||
use std::collections::{
|
use std::collections::{
|
||||||
BTreeMap,
|
BTreeMap,
|
||||||
};
|
};
|
||||||
|
@ -66,85 +67,93 @@ use query::{
|
||||||
/// A process is only permitted to have one open handle to each database. This manager
|
/// 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.
|
/// exists to enforce that constraint: don't open databases directly.
|
||||||
thread_local! {
|
thread_local! {
|
||||||
static STORES: RwLock<Stores> = {
|
static LOCAL_STORES: RefCell<Stores> = {
|
||||||
RwLock::new(Stores::new())
|
RefCell::new(Stores::new())
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref CONNECTIONS: BTreeMap<String, Arc<Conn>> = BTreeMap::default();
|
static ref CONNECTIONS: RwLock<BTreeMap<String, Arc<Conn>>> = RwLock::new(BTreeMap::default());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Stores {
|
pub struct Stores {
|
||||||
stores: BTreeMap<String, Store>,
|
connections: BTreeMap<String, Store>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Stores {
|
impl Stores {
|
||||||
fn new() -> Stores {
|
fn new() -> Stores {
|
||||||
Stores {
|
Stores {
|
||||||
stores: Default::default(),
|
connections: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Stores {
|
impl Stores {
|
||||||
fn is_open(path: &str) -> bool {
|
fn is_open(path: &str) -> bool {
|
||||||
Stores::singleton().read().unwrap().stores.contains_key(path)
|
CONNECTIONS.read().unwrap().contains_key(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn open(path: &str) -> Result<Store> {
|
fn is_open_on_thread(path: &str) -> bool {
|
||||||
|
LOCAL_STORES.with(|s| (*s.borrow()).connections.contains_key(path))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn open(path: &str) -> Result<&mut Store> {
|
||||||
let p = path.to_string();
|
let p = path.to_string();
|
||||||
let stores = Stores::singleton().read().unwrap().stores;
|
let connections = CONNECTIONS.read().unwrap();
|
||||||
let store = match stores.get(path) {
|
let store = match connections.get(path) {
|
||||||
Some(conn) => {
|
Some(conn) => {
|
||||||
let connection = CONNECTIONS.with(|s| s.entry(path.to_string()).or_insert_with(|| {
|
LOCAL_STORES.with(|s| {
|
||||||
::new_connection(path).unwrap()
|
let readable = *s.borrow();
|
||||||
}));
|
match readable.connections.get_mut(path) {
|
||||||
Store {
|
Some(store) => store,
|
||||||
conn: conn.clone(),
|
None => {
|
||||||
sqlite: *connection,
|
let store = Store {
|
||||||
}
|
conn: conn.clone(),
|
||||||
|
sqlite: ::new_connection(path).expect("connection"),
|
||||||
|
};
|
||||||
|
(*s.borrow_mut()).connections.insert(path.to_string(), store);
|
||||||
|
readable.connections.get_mut(path).unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
let mut connection = ::new_connection(path)?;
|
let store = Store::open(path)?;
|
||||||
CONNECTIONS.with(|s| s.insert(path.to_string(), connection));
|
CONNECTIONS.write().unwrap().insert(path.to_string(), store.conn().clone());
|
||||||
let conn = Arc::new(Conn::connect(&mut connection)?);
|
|
||||||
stores.insert(path.to_string(), conn);
|
LOCAL_STORES.with(|s| {
|
||||||
let store = Store {
|
(*s.borrow_mut()).connections.insert(path.to_string(), store);
|
||||||
conn: conn,
|
(*s.borrow()).connections.get_mut(path).unwrap()
|
||||||
sqlite: connection,
|
})
|
||||||
};
|
|
||||||
store
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Ok(store)
|
Ok(store)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(path: &str) -> Result<Option<&Store>> {
|
pub fn get(path: &str) -> Result<Option<&Store>> {
|
||||||
Ok(Stores::singleton().read().unwrap().stores.get(path))
|
Ok(LOCAL_STORES.with(|s| (*s.borrow()).connections.get(path)))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_mut(path: &str) -> Result<Option<&mut Store>> {
|
pub fn get_mut(path: &str) -> Result<Option<&mut Store>> {
|
||||||
Ok(Stores::singleton().read().unwrap().stores.get_mut(path))
|
Ok(LOCAL_STORES.with(|s| (*s.borrow_mut()).connections.get_mut(path)))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn connect(path: &str) -> Result<Store> {
|
pub fn connect(path: &str) -> Result<Store> {
|
||||||
let store = Stores::singleton().read().unwrap().stores.get_mut(path).ok_or(ErrorKind::StoreNotFound(path.to_string()))?;
|
let store = LOCAL_STORES.with(|s| (*s.borrow()).connections.get_mut(path)).ok_or(ErrorKind::StoreNotFound(path.to_string()))?;
|
||||||
let connection = ::new_connection(path)?;
|
let sqlite = ::new_connection(path)?;
|
||||||
store.fork(connection)
|
store.fork(sqlite)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn open_connections_for_store(path: &str) -> Result<usize> {
|
fn open_connections_for_store(path: &str) -> Result<usize> {
|
||||||
Ok(Arc::strong_count(Stores::singleton().read().unwrap().stores.get(path).ok_or(ErrorKind::StoreNotFound(path.to_string()))?.conn()))
|
Ok(Arc::strong_count(CONNECTIONS.read().unwrap().get(path).ok_or(ErrorKind::StoreNotFound(path.to_string()))?))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn close(path: &str) -> Result<()> {
|
pub fn close(path: &str) -> Result<()> {
|
||||||
|
LOCAL_STORES.with(|s| (*s.borrow_mut()).connections.remove(path));
|
||||||
if Stores::open_connections_for_store(path)? <= 1 {
|
if Stores::open_connections_for_store(path)? <= 1 {
|
||||||
Stores::singleton().write().unwrap().stores.remove(path).ok_or(ErrorKind::StoreNotFound(path.to_string()))?;
|
CONNECTIONS.write().unwrap().remove(path);
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
bail!(ErrorKind::StoreConnectionStillActive(path.to_string()))
|
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue