indexedlog: RotateLog::sync no longer errors out if latest is missing for read-only path

Summary:
In rare cases (ex. some other automation runs `rm -rf`), the `latest` file can
get deleted unexpectedly and cause an error. However, if `sync` is expected
to do a read-only refresh to load new data, it is harmless to stay "as-is" if
lastest cannot be read.

Reviewed By: xavierd

Differential Revision: D17763341

fbshipit-source-id: 6a493b8741b628f44709234bd69394d3b4eeb4de
This commit is contained in:
Jun Wu 2019-10-07 12:18:05 -07:00 committed by Facebook Github Bot
parent 80124113f3
commit 91790bc704

View File

@ -349,17 +349,22 @@ impl RotateLog {
if self.dir.is_none() {
return Ok(0);
}
let latest = read_latest(self.dir.as_ref().unwrap())?;
if self.writable_log().iter_dirty().nth(0).is_none() {
// Read-only path, no need to take directory lock.
if latest != self.latest {
// Latest changed. Re-load and write to the real latest Log.
// PERF(minor): This can be smarter by avoiding reloading some logs.
self.logs = read_logs(self.dir.as_ref().unwrap(), &self.open_options, latest)?;
self.latest = latest;
if let Ok(latest) = read_latest(self.dir.as_ref().unwrap()) {
if latest != self.latest {
// Latest changed. Re-load and write to the real latest Log.
// PERF(minor): This can be smarter by avoiding reloading some logs.
self.logs =
read_logs(self.dir.as_ref().unwrap(), &self.open_options, latest)?;
self.latest = latest;
}
self.writable_log().sync()?;
} else {
// If latest can not be read, do not error out.
// This RotateLog can still be used to answer queries.
}
self.writable_log().sync()?;
} else {
// Read-write path. Take the directory lock.
let dir = self.dir.clone().unwrap();
@ -1135,6 +1140,23 @@ mod tests {
assert!(size("2/log") < 100);
}
#[test]
fn test_sync_missing_latest() {
let dir = tempdir().unwrap();
let opts = OpenOptions::new()
.max_bytes_per_log(10000)
.max_log_count(10);
let mut rotate = opts.clone().create(true).open(&dir).unwrap();
rotate.append(vec![b'x'; 200]).unwrap();
rotate.sync().unwrap();
let mut rotate2 = opts.clone().open(&dir).unwrap();
fs::remove_file(dir.path().join(LATEST_FILE)).unwrap();
rotate2.sync().unwrap(); // not a failure
rotate2.append(vec![b'y'; 200]).unwrap();
rotate2.sync().unwrap_err(); // a failure
}
#[test]
fn test_repair_latest() {
assert_eq!(guess_latest(vec![]), 0);