mirror of
https://github.com/Llewellynvdm/zoxide.git
synced 2024-11-22 12:55:13 +00:00
Retry loop when persisting on Windows
This commit is contained in:
parent
314050f090
commit
3d432105e0
@ -5,7 +5,7 @@ use anyhow::{bail, Context, Result};
|
|||||||
use bincode::Options;
|
use bincode::Options;
|
||||||
use ordered_float::OrderedFloat;
|
use ordered_float::OrderedFloat;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tempfile::NamedTempFile;
|
use tempfile::{NamedTempFile, PersistError};
|
||||||
|
|
||||||
use std::cmp::Reverse;
|
use std::cmp::Reverse;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
@ -100,10 +100,24 @@ impl Store {
|
|||||||
})()
|
})()
|
||||||
.context("could not serialize store")?;
|
.context("could not serialize store")?;
|
||||||
|
|
||||||
let mut file = NamedTempFile::new_in(&self.data_dir).unwrap();
|
let mut file = NamedTempFile::new_in(&self.data_dir).with_context(|| {
|
||||||
|
format!(
|
||||||
|
"could not create temporary store in: {}",
|
||||||
|
self.data_dir.display()
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
let _ = file.as_file().set_len(buffer_size);
|
let _ = file.as_file().set_len(buffer_size);
|
||||||
file.write_all(&buffer).unwrap();
|
file.write_all(&buffer).with_context(|| {
|
||||||
file.persist(Self::get_path(&self.data_dir)).unwrap();
|
format!(
|
||||||
|
"could not write to temporary store: {}",
|
||||||
|
file.path().display()
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let path = Self::get_path(&self.data_dir);
|
||||||
|
persist(file, &path)
|
||||||
|
.with_context(|| format!("could not replace store: {}", path.display()))?;
|
||||||
|
|
||||||
self.modified = false;
|
self.modified = false;
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -184,3 +198,29 @@ impl Drop for Store {
|
|||||||
|
|
||||||
#[derive(Debug, Deserialize, Eq, PartialEq, Serialize)]
|
#[derive(Debug, Deserialize, Eq, PartialEq, Serialize)]
|
||||||
pub struct StoreVersion(pub u32);
|
pub struct StoreVersion(pub u32);
|
||||||
|
|
||||||
|
fn persist<P: AsRef<Path>>(mut file: NamedTempFile, path: P) -> Result<(), PersistError> {
|
||||||
|
if cfg!(windows) {
|
||||||
|
use std::thread;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
// File renames on Windows are not atomic and sometimes fail with `PermissionDenied`.
|
||||||
|
// This is extremely unlikely unless it's running in a loop on multiple threads.
|
||||||
|
// Nevertheless, we guard against it by retrying the rename a fixed number of times.
|
||||||
|
const MAX_TRIES: usize = 10;
|
||||||
|
for _ in 0..MAX_TRIES {
|
||||||
|
match file.persist(&path) {
|
||||||
|
Ok(_) => break,
|
||||||
|
Err(e) if e.error.kind() == io::ErrorKind::PermissionDenied => {
|
||||||
|
file = e.file;
|
||||||
|
thread::sleep(Duration::from_millis(50));
|
||||||
|
}
|
||||||
|
Err(e) => return Err(e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
file.persist(&path)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user