Skip to content
This repository was archived by the owner on May 22, 2025. It is now read-only.

Commit 09c2147

Browse files
authored
Merge pull request #1 from jupyterkat/buffered
moves write operations to a different thread and buffer it
2 parents f04a619 + fdcb19f commit 09c2147

File tree

2 files changed

+76
-33
lines changed

2 files changed

+76
-33
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ file = []
8383
git = ["git2", "chrono"]
8484
http = ["reqwest", "serde", "serde_json", "once_cell", "jobs"]
8585
json = ["serde", "serde_json"]
86-
log = ["chrono"]
86+
log = ["chrono", "flume"]
8787
sql = ["mysql", "serde", "serde_json", "once_cell", "dashmap", "jobs"]
8888
time = []
8989
toml = ["serde", "serde_json", "toml-dep"]

src/log.rs

Lines changed: 75 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,42 @@
11
use crate::error::Result;
22
use chrono::Utc;
33
use std::{
4-
cell::RefCell,
4+
cell::{Cell, RefCell},
55
collections::hash_map::{Entry, HashMap},
66
ffi::OsString,
77
fs,
88
fs::{File, OpenOptions},
99
io::Write,
1010
path::Path,
11+
sync::Once,
12+
thread::JoinHandle,
1113
};
1214

15+
static ONCE: Once = Once::new();
16+
1317
thread_local! {
14-
static FILE_MAP: RefCell<HashMap<OsString, File>> = RefCell::new(HashMap::new());
18+
static FILE_MAP: RefCell<HashMap<OsString, File>> = RefCell::new(HashMap::new()); //on worker thread
19+
static SENDER: RefCell<Option<flume::Sender<Box<(String, String, bool)>>>> = RefCell::new(None); //on main thread
20+
static HANDLE: Cell<Option<JoinHandle<()>>> = Cell::new(None); //on main thread
1521
}
1622

1723
byond_fn!(fn log_write(path, data, ...rest) {
18-
FILE_MAP.with(|cell| -> Result<()> {
19-
// open file
20-
let mut map = cell.borrow_mut();
21-
let path = Path::new(path as &str);
22-
let file = match map.entry(path.into()) {
23-
Entry::Occupied(elem) => elem.into_mut(),
24-
Entry::Vacant(elem) => elem.insert(open(path)?),
25-
};
26-
27-
if rest.first().map(|x| &**x) == Some("false") {
28-
// Write the data to the file with no accoutrements.
29-
write!(file, "{}", data)?;
30-
} else {
31-
// write first line, timestamped
32-
let mut iter = data.split('\n');
33-
if let Some(line) = iter.next() {
34-
write!(file, "[{}] {}\n", Utc::now().format("%F %T%.3f"), line)?;
35-
}
36-
37-
// write remaining lines
38-
for line in iter {
39-
write!(file, " - {}\n", line)?;
40-
}
41-
}
42-
43-
Ok(())
44-
}).err()
24+
init_worker();
25+
SENDER.with(|sender| {
26+
_ = sender.borrow().as_ref().unwrap().send(Box::new(
27+
(path.to_string(), data.to_string(), rest.first().map(|x| &**x) == Some("false"))
28+
))
29+
});
30+
Some("")
4531
});
4632

4733
byond_fn!(
4834
fn log_close_all() {
49-
FILE_MAP.with(|cell| {
50-
let mut map = cell.borrow_mut();
51-
map.clear();
35+
SENDER.with(|cell| cell.replace(None));
36+
HANDLE.with(|cell| {
37+
if let Some(handle) = cell.replace(None) {
38+
let _ = handle.join();
39+
};
5240
});
5341
Some("")
5442
}
@@ -61,3 +49,58 @@ fn open(path: &Path) -> Result<File> {
6149

6250
Ok(OpenOptions::new().append(true).create(true).open(path)?)
6351
}
52+
fn init_worker() {
53+
ONCE.call_once(|| {
54+
let (sender, receiver) = flume::unbounded();
55+
SENDER.with(|cell| *cell.borrow_mut() = Some(sender));
56+
HANDLE.with(|cell| {
57+
let handle = std::thread::spawn(move || {
58+
loop {
59+
let packet = receiver.recv();
60+
61+
if let Ok(packet) = packet {
62+
let (path, data, rest) = *packet;
63+
_ = FILE_MAP.with(|cell| -> Result<()> {
64+
// open file
65+
let mut map = cell.borrow_mut();
66+
let path = Path::new(&path);
67+
let file = match map.entry(path.into()) {
68+
Entry::Occupied(elem) => elem.into_mut(),
69+
Entry::Vacant(elem) => elem.insert(open(path)?),
70+
};
71+
72+
let mut buffer = std::io::BufWriter::new(file);
73+
74+
if rest {
75+
// Write the data to the file with no accoutrements.
76+
write!(buffer, "{}", data)?;
77+
} else {
78+
// write first line, timestamped
79+
let mut iter = data.split('\n');
80+
if let Some(line) = iter.next() {
81+
write!(
82+
buffer,
83+
"[{}] {}\n",
84+
Utc::now().format("%F %T%.3f"),
85+
line
86+
)?;
87+
}
88+
89+
// write remaining lines
90+
for line in iter {
91+
write!(buffer, " - {}\n", line)?;
92+
}
93+
}
94+
95+
Ok(())
96+
});
97+
} else {
98+
FILE_MAP.with(|cell| cell.borrow_mut().clear());
99+
return;
100+
}
101+
}
102+
});
103+
cell.set(Some(handle));
104+
});
105+
});
106+
}

0 commit comments

Comments
 (0)