Skip to content

Commit c37149e

Browse files
committed
Decouple persistence from main thread
1 parent c1ac725 commit c37149e

File tree

1 file changed

+53
-8
lines changed

1 file changed

+53
-8
lines changed

src/config.rs

Lines changed: 53 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ use std::{
77
collections::{BTreeSet, HashMap},
88
fs::{self, File},
99
path::{Path, PathBuf},
10-
sync::{Arc, RwLock},
10+
sync::{mpsc, Arc, RwLock},
11+
thread::{self, JoinHandle},
1112
};
1213

1314
const WINDOW_POS_KEY: &str = "window_pos";
@@ -26,26 +27,66 @@ struct ItemStore {
2627
items: HashMap<String, String>,
2728
}
2829

30+
#[derive(Eq, PartialEq)]
31+
enum Message {
32+
Persist,
33+
Exit,
34+
}
35+
2936
impl ItemStore {
30-
fn persist(&mut self) {
37+
fn persist(&self) {
3138
let file = ok!(File::create(&self.path));
3239
ron::ser::to_writer_pretty(file, &self.items, Default::default()).wrest();
3340
}
3441
}
3542

43+
struct ItemStoreThread {
44+
thread: Option<JoinHandle<()>>,
45+
tx: mpsc::Sender<Message>,
46+
}
47+
48+
impl Drop for ItemStoreThread {
49+
fn drop(&mut self) {
50+
self.tx.send(Message::Exit).wrest();
51+
if let Some(handle) = self.thread.take() {
52+
handle.join().wrest();
53+
}
54+
}
55+
}
56+
3657
#[derive(Clone)]
3758
pub struct Config {
3859
store: Arc<RwLock<ItemStore>>,
60+
thread: Arc<ItemStoreThread>,
3961
}
4062

4163
impl Config {
4264
pub fn new() -> Option<Self> {
4365
let path = Self::path()?;
4466
let items = Self::load(&path);
45-
let store = ItemStore { path, items };
46-
Some(Self {
47-
store: Arc::new(RwLock::new(store)),
48-
})
67+
let store = Arc::new(RwLock::new(ItemStore { path, items }));
68+
let (tx, rx) = mpsc::channel::<Message>();
69+
let thread = {
70+
let store = store.clone();
71+
Some(thread::spawn(move || loop {
72+
// Wait for a message.
73+
if rx.recv().wrest() == Message::Exit {
74+
return;
75+
}
76+
77+
// Only the most recent persist message is needed.
78+
while let Ok(msg) = rx.try_recv() {
79+
if msg == Message::Exit {
80+
return;
81+
}
82+
}
83+
84+
store.read().wrest().persist();
85+
}))
86+
};
87+
88+
let thread = Arc::new(ItemStoreThread { thread, tx });
89+
Some(Self { store, thread })
4990
}
5091

5192
pub fn get_window_pos(&self) -> Option<Pos2> {
@@ -237,16 +278,20 @@ impl Config {
237278
fn set(&mut self, key: &str, item: String) {
238279
let mut lock = self.store.write().wrest();
239280
lock.items.insert(key.to_owned(), item);
240-
lock.persist();
281+
self.persist();
241282
}
242283

243284
fn remove(&mut self, key: &str) {
244285
let mut lock = self.store.write().wrest();
245286
if lock.items.remove(key).is_some() {
246-
lock.persist();
287+
self.persist();
247288
}
248289
}
249290

291+
fn persist(&self) {
292+
self.thread.tx.send(Message::Persist).wrest();
293+
}
294+
250295
fn get_sota_config_path() -> Option<PathBuf> {
251296
let path = dirs::config_dir()?;
252297
Some(path.join("Portalarium").join("Shroud of the Avatar"))

0 commit comments

Comments
 (0)