Skip to content

Commit 2b8d90a

Browse files
committed
Replace race-y metadata call with DirEntry::metadata
Previously, the internal `dir_entry_is_key` method would take a path argument, which would risk a race when the respective entry was modified in the time between the original `fs::read_dir` call and the `Path::metadata` call. Here, we instead have it take a `DirEntry` argument, which--at least on some platforms--should allow us to avoid this race as `DirEntry::metadata` would return the original (cached) metadata.
1 parent ee4211e commit 2b8d90a

File tree

1 file changed

+20
-16
lines changed

1 file changed

+20
-16
lines changed

lightning-persister/src/fs_store.rs

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -316,11 +316,11 @@ impl KVStore for FilesystemStore {
316316
let entry = entry?;
317317
let p = entry.path();
318318

319-
if !dir_entry_is_key(&p)? {
319+
if !dir_entry_is_key(&entry)? {
320320
continue;
321321
}
322322

323-
let key = get_key_from_dir_entry(&p, &prefixed_dest)?;
323+
let key = git_key_from_dir_entry_path(&p, &prefixed_dest)?;
324324

325325
keys.push(key);
326326
}
@@ -331,7 +331,8 @@ impl KVStore for FilesystemStore {
331331
}
332332
}
333333

334-
fn dir_entry_is_key(p: &Path) -> Result<bool, lightning::io::Error> {
334+
fn dir_entry_is_key(dir_entry: &fs::DirEntry) -> Result<bool, lightning::io::Error> {
335+
let p = dir_entry.path();
335336
if let Some(ext) = p.extension() {
336337
#[cfg(target_os = "windows")]
337338
{
@@ -346,7 +347,7 @@ fn dir_entry_is_key(p: &Path) -> Result<bool, lightning::io::Error> {
346347
}
347348
}
348349

349-
let metadata = p.metadata().map_err(|e| {
350+
let metadata = dir_entry.metadata().map_err(|e| {
350351
let msg = format!(
351352
"Failed to list keys at path {}: {}",
352353
PrintableString(p.to_str().unwrap_or_default()),
@@ -377,7 +378,7 @@ fn dir_entry_is_key(p: &Path) -> Result<bool, lightning::io::Error> {
377378
Ok(true)
378379
}
379380

380-
fn get_key_from_dir_entry(p: &Path, base_path: &Path) -> Result<String, lightning::io::Error> {
381+
fn git_key_from_dir_entry_path(p: &Path, base_path: &Path) -> Result<String, lightning::io::Error> {
381382
match p.strip_prefix(&base_path) {
382383
Ok(stripped_path) => {
383384
if let Some(relative_path) = stripped_path.to_str() {
@@ -435,24 +436,27 @@ impl MigratableKVStore for FilesystemStore {
435436
let mut keys = Vec::new();
436437

437438
'primary_loop: for primary_entry in fs::read_dir(prefixed_dest)? {
438-
let primary_path = primary_entry?.path();
439+
let primary_entry = primary_entry?;
440+
let primary_path = primary_entry.path();
439441

440-
if dir_entry_is_key(&primary_path)? {
442+
if dir_entry_is_key(&primary_entry)? {
441443
let primary_namespace = String::new();
442444
let secondary_namespace = String::new();
443-
let key = get_key_from_dir_entry(&primary_path, prefixed_dest)?;
445+
let key = git_key_from_dir_entry_path(&primary_path, prefixed_dest)?;
444446
keys.push((primary_namespace, secondary_namespace, key));
445447
continue 'primary_loop;
446448
}
447449

448450
// The primary_entry is actually also a directory.
449451
'secondary_loop: for secondary_entry in fs::read_dir(&primary_path)? {
450-
let secondary_path = secondary_entry?.path();
452+
let secondary_entry = secondary_entry?;
453+
let secondary_path = secondary_entry.path();
451454

452-
if dir_entry_is_key(&secondary_path)? {
453-
let primary_namespace = get_key_from_dir_entry(&primary_path, prefixed_dest)?;
455+
if dir_entry_is_key(&secondary_entry)? {
456+
let primary_namespace =
457+
git_key_from_dir_entry_path(&primary_path, prefixed_dest)?;
454458
let secondary_namespace = String::new();
455-
let key = get_key_from_dir_entry(&secondary_path, &primary_path)?;
459+
let key = git_key_from_dir_entry_path(&secondary_path, &primary_path)?;
456460
keys.push((primary_namespace, secondary_namespace, key));
457461
continue 'secondary_loop;
458462
}
@@ -462,12 +466,12 @@ impl MigratableKVStore for FilesystemStore {
462466
let tertiary_entry = tertiary_entry?;
463467
let tertiary_path = tertiary_entry.path();
464468

465-
if dir_entry_is_key(&tertiary_path)? {
469+
if dir_entry_is_key(&tertiary_entry)? {
466470
let primary_namespace =
467-
get_key_from_dir_entry(&primary_path, prefixed_dest)?;
471+
git_key_from_dir_entry_path(&primary_path, prefixed_dest)?;
468472
let secondary_namespace =
469-
get_key_from_dir_entry(&secondary_path, &primary_path)?;
470-
let key = get_key_from_dir_entry(&tertiary_path, &secondary_path)?;
473+
git_key_from_dir_entry_path(&secondary_path, &primary_path)?;
474+
let key = git_key_from_dir_entry_path(&tertiary_path, &secondary_path)?;
471475
keys.push((primary_namespace, secondary_namespace, key));
472476
} else {
473477
debug_assert!(

0 commit comments

Comments
 (0)