]> git.mikk.net Git - mtbl-rs/commitdiff
Refactor fileset
authorChris Mikkelson <cmikk@fsi.io>
Thu, 12 Sep 2024 23:36:50 +0000 (18:36 -0500)
committerChris Mikkelson <cmikk@fsi.io>
Thu, 12 Sep 2024 23:36:50 +0000 (18:36 -0500)
Implement lazy loading on first use and error reporting.

src/fileset.rs

index ee5e6452bb0bc0d818abcc8433bbfb51e3486a2c..36a8ea4a406e3d9d556cb31341a86edfa5ccf247 100644 (file)
@@ -7,14 +7,13 @@ use crate::Result;
 use std::collections::HashMap;
 use std::path::{Path, PathBuf};
 use std::sync::Mutex;
-use std::time::{Duration, Instant};
+use std::time::{Duration, SystemTime};
 
 pub struct Fileset {
     fs_path: PathBuf,
-    last_reload: Instant,
+    last_reload: SystemTime,
     reload_interval: Duration,
-    readers: Mutex<HashMap<PathBuf, (Reader<Mmap>, Instant)>>,
-    merger: Mutex<Option<Merger<Reader<Mmap>>>>,
+    readers: Mutex<HashMap<PathBuf, (Reader<Mmap>, SystemTime)>>,
 }
 
 fn load_fs_file(f: impl AsRef<Path>) -> Result<Vec<PathBuf>> {
@@ -26,50 +25,67 @@ fn load_fs_file(f: impl AsRef<Path>) -> Result<Vec<PathBuf>> {
 
 impl Fileset {
     pub fn new(fname: impl AsRef<Path>) -> Self {
-        let mut res = Self {
+        Self {
             fs_path: PathBuf::new().with_file_name(fname.as_ref()),
-            last_reload: Instant::now(),
+            last_reload: SystemTime::now() - Duration::new(2, 0),
             reload_interval: Duration::new(1, 0),
             readers: Mutex::new(HashMap::new()),
-            merger: Mutex::new(None),
-        };
-        res.force_reload();
-        res
+        }
     }
 
-    fn force_reload(&mut self) {
-        let files = load_fs_file(&self.fs_path).unwrap();
-        let now = Instant::now();
+    pub fn reload_interval(mut self, d: Duration) -> Self {
+        self.reload_interval = d;
+        self
+    }
 
-        let mut readers = self.readers.lock().unwrap();
-        if self.last_reload > now {
-            return;
+    fn reload(&mut self) -> Result<()> {
+        let now = SystemTime::now();
+        if now.duration_since(self.last_reload)? < self.reload_interval {
+            return Ok(());
         }
-        files
-            .iter()
-            .map(|f| match readers.get(f) {
+
+        let mdata = std::fs::metadata(&self.fs_path)?;
+        if !mdata.is_file() {
+            return Err(format!("{:#?} is not a regular file", &self.fs_path).into());
+        }
+
+        if mdata.modified()? <= self.last_reload {
+            self.last_reload = now;
+            return Ok(());
+        }
+
+        let files = load_fs_file(&self.fs_path)?;
+
+        let mut readers = self.readers.lock().unwrap();
+        files.iter().for_each(|f| {
+            match readers.get(f) {
                 Some(_) => None,
                 None => readers.insert(f.to_path_buf(), (crate::reader::from_file(f), now)),
-            })
-            .count(); // must use
+            };
+        });
 
         let clean = readers
             .iter()
             .filter(|(_, (_, t))| *t < now)
             .map(|(f, _)| f.clone())
             .collect::<Vec<_>>();
+
         clean.iter().for_each(|f| {
             readers.remove(f);
             ()
         });
-        let mut merger = self.merger.lock().unwrap();
-        merger.replace(Merger::from(readers.iter().map(|(_, (r, _))| r.clone())));
+
         self.last_reload = now;
+        Ok(())
     }
 
-    fn reload(&mut self) {
-        if Instant::now().duration_since(self.last_reload) > self.reload_interval {
-            self.force_reload();
-        }
+    pub fn readers(&mut self) -> Result<Vec<Reader<Mmap>>> {
+        self.reload()?;
+        let readers = self.readers.lock().unwrap();
+        Ok(readers.iter().map(|(_, (r, _))| r.clone()).collect())
+    }
+
+    pub fn merger(&mut self) -> Result<Merger<Reader<Mmap>>> {
+        Ok(Merger::from(self.readers()?))
     }
 }