Only lifetime issues with thread_local remaining

This commit is contained in:
Emily Toop 2018-05-29 15:57:19 +01:00
parent baa7cb4f8f
commit 9e6d6c2834

View file

@ -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(())
} }
} }