chore: finalize redb migration for all memory stores
This commit is contained in:
1 parent
9a8b6e52e9
commit
721f564910
4 files changed
+107
-88
No files matched your search
+36
-65
@@ -1,84 +1,55 @@
|
||||
use redb::{Database, ReadableDatabase, TableDefinition};
|
||||
use serde::{Serialize, de::DeserializeOwned};
|
||||
use std::fs;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::RwLock;
|
||||
use std::time::SystemTime;
|
||||
use std::sync::{Arc, RwLock};
|
||||
|
||||
pub fn read_json_file<T: DeserializeOwned + Default>(path: &Path) -> T {
|
||||
if let Ok(data) = fs::read(path)
|
||||
&& let Ok(parsed) = serde_json::from_slice(&data)
|
||||
{
|
||||
return parsed;
|
||||
}
|
||||
let bak_path = path.with_extension("json.bak");
|
||||
if let Ok(data) = fs::read(&bak_path)
|
||||
&& let Ok(parsed) = serde_json::from_slice(&data)
|
||||
{
|
||||
let _ = fs::write(path, data);
|
||||
return parsed;
|
||||
}
|
||||
T::default()
|
||||
}
|
||||
|
||||
pub fn write_json_atomic<T: Serialize>(path: &Path, data: &T) -> std::io::Result<()> {
|
||||
if path.exists() {
|
||||
let bak_path = path.with_extension("json.bak");
|
||||
let _ = fs::copy(path, &bak_path);
|
||||
}
|
||||
let tmp_path = path.with_extension("json.tmp");
|
||||
let json_data = serde_json::to_string_pretty(data)?;
|
||||
fs::write(&tmp_path, json_data)?;
|
||||
fs::rename(&tmp_path, path)
|
||||
}
|
||||
pub const STORE_TABLE: TableDefinition<&str, &[u8]> = TableDefinition::new("store");
|
||||
|
||||
pub struct Store<T> {
|
||||
pub path: PathBuf,
|
||||
pub cache: RwLock<(T, SystemTime)>,
|
||||
pub key: String,
|
||||
pub db: Arc<Database>,
|
||||
pub cache: RwLock<T>,
|
||||
}
|
||||
|
||||
impl<T: DeserializeOwned + Default + Serialize + Clone> Store<T> {
|
||||
fn mtime(&self) -> SystemTime {
|
||||
fs::metadata(&self.path)
|
||||
.and_then(|m| m.modified())
|
||||
.unwrap_or(SystemTime::UNIX_EPOCH)
|
||||
pub fn new(key: &str, db: Arc<Database>) -> Self {
|
||||
let initial_data = Self::load_from_db(key, &db);
|
||||
Self {
|
||||
key: key.to_string(),
|
||||
db,
|
||||
cache: RwLock::new(initial_data),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(path: PathBuf) -> Self {
|
||||
let mtime = fs::metadata(&path)
|
||||
.and_then(|m| m.modified())
|
||||
.unwrap_or(SystemTime::UNIX_EPOCH);
|
||||
let initial_data = read_json_file(&path);
|
||||
Self {
|
||||
path,
|
||||
cache: RwLock::new((initial_data, mtime)),
|
||||
fn load_from_db(key: &str, db: &Database) -> T {
|
||||
let read_txn = db.begin_read().unwrap();
|
||||
if let Ok(table) = read_txn.open_table(STORE_TABLE) {
|
||||
if let Ok(Some(value)) = table.get(key) {
|
||||
if let Ok(parsed) = serde_json::from_slice::<T>(value.value()) {
|
||||
return parsed;
|
||||
}
|
||||
}
|
||||
}
|
||||
T::default()
|
||||
}
|
||||
|
||||
fn save_to_db(key: &str, db: &Database, data: &T) {
|
||||
let write_txn = db.begin_write().unwrap();
|
||||
{
|
||||
let mut table = write_txn.open_table(STORE_TABLE).unwrap();
|
||||
let json_data = serde_json::to_vec(data).unwrap();
|
||||
table.insert(key, json_data.as_slice()).unwrap();
|
||||
}
|
||||
write_txn.commit().unwrap();
|
||||
}
|
||||
|
||||
pub fn read(&self) -> T {
|
||||
let current_mtime = self.mtime();
|
||||
{
|
||||
let lock = self.cache.read().unwrap();
|
||||
if lock.1 == current_mtime {
|
||||
return lock.0.clone();
|
||||
}
|
||||
}
|
||||
let mut lock = self.cache.write().unwrap();
|
||||
let new_mtime = self.mtime();
|
||||
if lock.1 != new_mtime {
|
||||
lock.0 = read_json_file(&self.path);
|
||||
lock.1 = new_mtime;
|
||||
}
|
||||
lock.0.clone()
|
||||
let lock = self.cache.read().unwrap();
|
||||
lock.clone()
|
||||
}
|
||||
|
||||
pub fn modify<F: FnOnce(&mut T)>(&self, f: F) {
|
||||
let mut lock = self.cache.write().unwrap();
|
||||
let current_mtime = self.mtime();
|
||||
if lock.1 != current_mtime {
|
||||
lock.0 = read_json_file(&self.path);
|
||||
}
|
||||
f(&mut lock.0);
|
||||
let _ = write_json_atomic(&self.path, &lock.0);
|
||||
lock.1 = self.mtime();
|
||||
f(&mut lock);
|
||||
Self::save_to_db(&self.key, &self.db, &lock);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user