2021-09-16 04:35:55 +00:00
|
|
|
use crate::errors::UserError;
|
2021-07-10 08:27:20 +00:00
|
|
|
use flowy_database::{DBConnection, Database};
|
2021-08-31 15:01:46 +00:00
|
|
|
use flowy_sqlite::ConnectionPool;
|
2021-07-09 15:31:44 +00:00
|
|
|
use lazy_static::lazy_static;
|
2021-07-18 01:03:21 +00:00
|
|
|
use once_cell::sync::Lazy;
|
2021-09-04 07:12:53 +00:00
|
|
|
use parking_lot::{Mutex, RwLock};
|
2021-09-03 08:43:03 +00:00
|
|
|
use std::{collections::HashMap, sync::Arc, time::Duration};
|
2021-07-09 15:31:44 +00:00
|
|
|
lazy_static! {
|
2021-07-10 08:27:20 +00:00
|
|
|
static ref DB: RwLock<Option<Database>> = RwLock::new(None);
|
2021-07-09 15:31:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) struct UserDB {
|
|
|
|
db_dir: String,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl UserDB {
|
2021-10-01 11:39:08 +00:00
|
|
|
pub(crate) fn new(db_dir: &str) -> Self {
|
|
|
|
Self {
|
|
|
|
db_dir: db_dir.to_owned(),
|
|
|
|
}
|
|
|
|
}
|
2021-07-09 15:31:44 +00:00
|
|
|
|
|
|
|
fn open_user_db(&self, user_id: &str) -> Result<(), UserError> {
|
2021-07-18 15:56:36 +00:00
|
|
|
if user_id.is_empty() {
|
2021-09-16 04:35:55 +00:00
|
|
|
return Err(UserError::internal().context("user id is empty"));
|
2021-07-18 15:56:36 +00:00
|
|
|
}
|
2021-07-18 01:03:21 +00:00
|
|
|
|
2021-09-03 08:43:03 +00:00
|
|
|
log::info!("open user db {}", user_id);
|
2021-07-10 08:27:20 +00:00
|
|
|
let dir = format!("{}/{}", self.db_dir, user_id);
|
2021-07-11 13:54:55 +00:00
|
|
|
let db = flowy_database::init(&dir).map_err(|e| {
|
2021-09-03 08:43:03 +00:00
|
|
|
log::error!("init user db failed, {:?}, user_id: {}", e, user_id);
|
2021-09-16 04:35:55 +00:00
|
|
|
UserError::internal().context(e)
|
2021-07-11 13:54:55 +00:00
|
|
|
})?;
|
|
|
|
|
2021-09-03 08:43:03 +00:00
|
|
|
match DB_MAP.try_write_for(Duration::from_millis(300)) {
|
2021-09-16 04:35:55 +00:00
|
|
|
None => Err(UserError::internal().context(format!("Acquire write lock to save user db failed"))),
|
2021-09-03 08:43:03 +00:00
|
|
|
Some(mut write_guard) => {
|
|
|
|
write_guard.insert(user_id.to_owned(), db);
|
|
|
|
Ok(())
|
|
|
|
},
|
|
|
|
}
|
2021-07-09 15:31:44 +00:00
|
|
|
}
|
|
|
|
|
2021-07-18 01:03:21 +00:00
|
|
|
pub(crate) fn close_user_db(&self, user_id: &str) -> Result<(), UserError> {
|
2021-09-03 08:43:03 +00:00
|
|
|
match DB_MAP.try_write_for(Duration::from_millis(300)) {
|
2021-09-16 04:35:55 +00:00
|
|
|
None => Err(UserError::internal().context(format!("Acquire write lock to close user db failed"))),
|
2021-09-03 08:43:03 +00:00
|
|
|
Some(mut write_guard) => {
|
|
|
|
set_user_db_init(false, user_id);
|
|
|
|
write_guard.remove(user_id);
|
|
|
|
Ok(())
|
|
|
|
},
|
|
|
|
}
|
2021-07-09 15:31:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn get_connection(&self, user_id: &str) -> Result<DBConnection, UserError> {
|
2021-08-31 15:01:46 +00:00
|
|
|
let conn = self.get_pool(user_id)?.get()?;
|
|
|
|
Ok(conn)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn get_pool(&self, user_id: &str) -> Result<Arc<ConnectionPool>, UserError> {
|
2021-09-03 08:43:03 +00:00
|
|
|
// Opti: INIT_LOCK try to lock the INIT_RECORD accesses. Because the write guard
|
|
|
|
// can not nested in the read guard that will cause the deadlock.
|
|
|
|
match INIT_LOCK.try_lock_for(Duration::from_millis(300)) {
|
|
|
|
None => log::error!("get_pool fail"),
|
|
|
|
Some(_) => {
|
|
|
|
if !is_user_db_init(user_id) {
|
|
|
|
let _ = self.open_user_db(user_id)?;
|
|
|
|
set_user_db_init(true, user_id);
|
|
|
|
}
|
|
|
|
},
|
2021-07-09 15:31:44 +00:00
|
|
|
}
|
|
|
|
|
2021-09-03 08:43:03 +00:00
|
|
|
match DB_MAP.try_read_for(Duration::from_millis(300)) {
|
2021-09-16 04:35:55 +00:00
|
|
|
None => Err(UserError::internal().context(format!("Acquire read lock to read user db failed"))),
|
2021-09-03 08:43:03 +00:00
|
|
|
Some(read_guard) => match read_guard.get(user_id) {
|
2021-09-16 04:35:55 +00:00
|
|
|
None => Err(UserError::internal().context("Get connection failed. The database is not initialization")),
|
2021-09-03 08:43:03 +00:00
|
|
|
Some(database) => Ok(database.get_pool()),
|
|
|
|
},
|
2021-07-09 15:31:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-18 01:03:21 +00:00
|
|
|
lazy_static! {
|
|
|
|
static ref DB_MAP: RwLock<HashMap<String, Database>> = RwLock::new(HashMap::new());
|
2021-07-11 07:33:19 +00:00
|
|
|
}
|
2021-07-18 01:03:21 +00:00
|
|
|
|
2021-09-03 08:43:03 +00:00
|
|
|
static INIT_LOCK: Lazy<Mutex<()>> = Lazy::new(|| Mutex::new(()));
|
|
|
|
static INIT_RECORD: Lazy<Mutex<HashMap<String, bool>>> = Lazy::new(|| Mutex::new(HashMap::new()));
|
2021-07-18 01:03:21 +00:00
|
|
|
fn set_user_db_init(is_init: bool, user_id: &str) {
|
2021-09-03 08:43:03 +00:00
|
|
|
let mut record = INIT_RECORD.lock();
|
|
|
|
record.insert(user_id.to_owned(), is_init);
|
2021-07-11 07:33:19 +00:00
|
|
|
}
|
|
|
|
|
2021-07-18 01:03:21 +00:00
|
|
|
fn is_user_db_init(user_id: &str) -> bool {
|
2021-09-03 08:43:03 +00:00
|
|
|
match INIT_RECORD.lock().get(user_id) {
|
2021-07-18 01:03:21 +00:00
|
|
|
None => false,
|
|
|
|
Some(flag) => flag.clone(),
|
|
|
|
}
|
|
|
|
}
|
2021-07-11 07:33:19 +00:00
|
|
|
|
2021-07-09 15:31:44 +00:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
2021-07-10 16:07:37 +00:00
|
|
|
|
2021-07-09 15:31:44 +00:00
|
|
|
#[test]
|
|
|
|
fn init_db_test() {
|
|
|
|
// init_user_db(".").unwrap();
|
|
|
|
}
|
|
|
|
}
|