mirror of
https://github.com/facebook/sapling.git
synced 2024-10-07 07:17:55 +03:00
indexedlog: recover from partially created LogRotate
Summary: In some rare cases, it's possible that the "latest" file is created, but the matching indexedlog isn't. Let's nicely recover from this by creating the indexedlog in this case. Reviewed By: kulshrax Differential Revision: D16554090 fbshipit-source-id: 6b68d7806662b511917655a71c3a3c15ad6e1f64
This commit is contained in:
parent
bd75a8e099
commit
e30a0b41f3
@ -118,20 +118,27 @@ impl OpenOptions {
|
||||
pub fn open(self, dir: impl AsRef<Path>) -> Fallible<RotateLog> {
|
||||
let dir = dir.as_ref();
|
||||
|
||||
let latest_path = dir.join(LATEST_FILE);
|
||||
let (latest, logs) = if !self.log_open_options.create || latest_path.exists() {
|
||||
let latest = read_latest(dir)?;
|
||||
(latest, read_logs(dir, &self, latest)?)
|
||||
} else {
|
||||
fs::create_dir_all(dir)?;
|
||||
let mut lock_file = open_dir(dir)?;
|
||||
let _lock = ScopedFileLock::new(&mut lock_file, true)?;
|
||||
if latest_path.exists() {
|
||||
// Two creates raced and the other one has created basic files.
|
||||
let latest = read_latest(dir)?;
|
||||
(latest, read_logs(dir, &self, latest)?)
|
||||
} else {
|
||||
(0, vec![create_empty_log(Some(dir), &self, 0)?])
|
||||
let latest_and_log = read_latest_and_logs(dir, &self);
|
||||
|
||||
let (latest, logs) = match latest_and_log {
|
||||
Ok((latest, logs)) => (latest, logs),
|
||||
Err(e) => {
|
||||
if !self.log_open_options.create {
|
||||
return Err(e);
|
||||
} else {
|
||||
fs::create_dir_all(dir)?;
|
||||
let mut lock_file = open_dir(dir)?;
|
||||
let _lock = ScopedFileLock::new(&mut lock_file, true)?;
|
||||
|
||||
let latest_and_log = read_latest_and_logs(dir, &self);
|
||||
|
||||
// two creates raced and the other one has created basic files.
|
||||
if let Ok((latest, logs)) = latest_and_log {
|
||||
(latest, logs)
|
||||
} else {
|
||||
(0, vec![create_empty_log(Some(dir), &self, 0)?])
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -464,6 +471,11 @@ fn read_logs(dir: &Path, open_options: &OpenOptions, latest: u8) -> Fallible<Vec
|
||||
}
|
||||
}
|
||||
|
||||
fn read_latest_and_logs(dir: &Path, open_options: &OpenOptions) -> Fallible<(u8, Vec<Log>)> {
|
||||
let latest = read_latest(dir)?;
|
||||
Ok((latest, read_logs(dir, open_options, latest)?))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@ -777,4 +789,22 @@ mod tests {
|
||||
vec![a, b]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn recover_from_partially_created() -> Fallible<()> {
|
||||
let dir = tempdir().unwrap();
|
||||
let rotate = OpenOptions::new().create(true).open(&dir)?;
|
||||
drop(rotate);
|
||||
|
||||
for dirent in fs::read_dir(&dir)? {
|
||||
let dirent = dirent?;
|
||||
let path = dirent.path();
|
||||
if path.is_dir() {
|
||||
fs::remove_dir_all(path)?;
|
||||
}
|
||||
}
|
||||
|
||||
let _ = OpenOptions::new().create(true).open(&dir)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user