diff options
Diffstat (limited to 'src/swarm/state_file.rs')
| -rw-r--r-- | src/swarm/state_file.rs | 53 |
1 files changed, 33 insertions, 20 deletions
diff --git a/src/swarm/state_file.rs b/src/swarm/state_file.rs index 0a9913d..79caec2 100644 --- a/src/swarm/state_file.rs +++ b/src/swarm/state_file.rs @@ -38,6 +38,8 @@ pub(crate) struct Remembered { pub(crate) struct StateFile { path: PathBuf, + /// Bytes read when opened, if there was a file (`swarm::stats`, disk). + read_bytes: Option<u64>, // A std mutex: never held across an await. inner: Mutex<Inner>, } @@ -53,24 +55,28 @@ impl StateFile { /// Opens `path`, returning what it remembers. A missing file remembers nothing; an /// unreadable one is moved aside (`.bad`) and logged, and remembers nothing either. pub(crate) fn open(path: PathBuf) -> (Self, Option<Remembered>) { + let mut read_bytes = None; let remembered = match std::fs::read(&path) { - Ok(bytes) => match serde_json::from_slice::<Remembered>(&bytes) { - Ok(remembered) if !remembered.swarm_id.is_empty() => Some(remembered), - Ok(_) => None, - Err(error) => { - let aside = with_suffix(&path, ".bad"); - error!( - path = %path.display(), - moved_to = %aside.display(), - error = %error, - "Unreadable state file; moving it aside and remembering nothing" - ); - if let Err(error) = std::fs::rename(&path, &aside) { - warn!(error = %error, "Couldn't move the state file aside"); + Ok(bytes) => { + read_bytes = Some(bytes.len() as u64); + match serde_json::from_slice::<Remembered>(&bytes) { + Ok(remembered) if !remembered.swarm_id.is_empty() => Some(remembered), + Ok(_) => None, + Err(error) => { + let aside = with_suffix(&path, ".bad"); + error!( + path = %path.display(), + moved_to = %aside.display(), + error = %error, + "Unreadable state file; moving it aside and remembering nothing" + ); + if let Err(error) = std::fs::rename(&path, &aside) { + warn!(error = %error, "Couldn't move the state file aside"); + } + None } - None } - }, + } Err(error) if error.kind() == std::io::ErrorKind::NotFound => None, Err(error) => { error!(path = %path.display(), error = %error, "Couldn't read the state file; remembering nothing"); @@ -79,6 +85,7 @@ impl StateFile { }; let file = Self { path, + read_bytes, inner: Mutex::new(Inner { written: remembered.clone(), ..Inner::default() @@ -87,19 +94,24 @@ impl StateFile { (file, remembered) } + pub(crate) fn read_bytes(&self) -> Option<u64> { + self.read_bytes + } + fn lock(&self) -> MutexGuard<'_, Inner> { self.inner .lock() .unwrap_or_else(|poisoned| poisoned.into_inner()) } - fn write(&self, remembered: &Remembered) -> std::io::Result<()> { - let bytes = serde_json::to_vec_pretty(remembered)?; + /// Returns the bytes written. + fn write(&self, remembered: &Remembered) -> std::io::Result<u64> { + let mut bytes = serde_json::to_vec_pretty(remembered)?; + bytes.push(b'\n'); let temporary = with_suffix(&self.path, ".tmp"); { let mut file = std::fs::File::create(&temporary)?; file.write_all(&bytes)?; - file.write_all(b"\n")?; file.sync_all()?; } std::fs::rename(&temporary, &self.path)?; @@ -109,7 +121,7 @@ impl StateFile { let _ = dir.sync_all(); } } - Ok(()) + Ok(bytes.len() as u64) } } @@ -169,7 +181,8 @@ pub(crate) async fn update(state: &AppState, now: bool) { let writer = std::sync::Arc::clone(&file); let content = remembered.clone(); match tokio::task::spawn_blocking(move || writer.write(&content)).await { - Ok(Ok(())) => { + Ok(Ok(bytes)) => { + state.stats.disk_written(bytes); info!( path = %file.path.display(), seeds = remembered.seeds.len(), |
