diff --git a/src/post.rs b/src/post.rs
index e1477ac..487cf19 100644
--- a/src/post.rs
+++ b/src/post.rs
@@ -99,10 +99,13 @@ pub struct LoaderCache {
frame_sender: Sender,
loader: Arc,
workers: ThreadPool,
+ num_workers: u32,
+ busy_workers: u32,
}
impl LoaderCache {
pub fn new(loader: Loader, size: usize) -> Self {
+ let num_workers = 16;
let loader = Arc::new(loader);
let (sender, receiver) = mpsc::channel();
@@ -111,7 +114,9 @@ impl LoaderCache {
ready_frames: receiver,
frame_sender: sender,
loader,
- workers: ThreadPoolBuilder::new().num_threads(8).build().unwrap(),
+ workers: ThreadPoolBuilder::new().num_threads(num_workers as _).build().unwrap(),
+ num_workers,
+ busy_workers: 0,
}
}
pub fn load_first(&mut self) -> Arc {
@@ -124,16 +129,19 @@ impl LoaderCache {
}
fn load_from_paths(&mut self, paths: Paths, rel: isize) -> Arc {
// Prefetch this path + a couple more based on access pattern
- let paths_to_fetch = (0..5).into_iter()
+ self.tend_cache_nonblocking();
+ self.fetch_async(paths.path(), 0);
+
+ let paths_to_prefetch = (1..5).into_iter()
.map(|i| paths.get_rel(i*rel))
.dedup();
- for path in paths_to_fetch {
- self.fetch_async(path);
+ for path in paths_to_prefetch {
+ self.fetch_async(path, 2 /* leave some space in case we need something more urgent */);
}
+
self.get_or_tend(paths.path())
}
fn get_or_tend(&mut self, path: PathBuf) -> Arc {
- self.tend_cache_nonblocking();
if let Some(cached) = self.cache.get(&path) {
return cached.clone();
}
@@ -141,9 +149,18 @@ impl LoaderCache {
self.tend_cache(path)
}
- fn fetch_async(&self, path: PathBuf) {
+ /// If not cached, fetch the Frame in a background worker, but reserve at
+ /// least `reserved` workers (for higher priority work).
+ fn fetch_async(&mut self, path: PathBuf, reserved: u32) {
+ let cached = self.cache.get(&path).is_some();
+ let free_workers = self.busy_workers + reserved < self.num_workers;
+ if cached || !free_workers {
+ return;
+ }
+
let sender = self.frame_sender.clone();
let loader = self.loader.clone();
+ self.busy_workers += 1;
self.workers.spawn(move || {
let _ = sender.send(loader.load(&path));
});
@@ -153,6 +170,7 @@ impl LoaderCache {
loop {
let frame = Arc::new(self.ready_frames.recv().unwrap());
self.cache.put(frame.path.clone(), frame.clone());
+ self.busy_workers -= 1;
if frame.path == path {
return frame;
}