Skip to content

Commit 53917c3

Browse files
fix(storage): avoid git sync temp path collisions (#248)
Co-authored-by: Andrew Briscoe <awb@presempathy.com>
1 parent 5efec13 commit 53917c3

1 file changed

Lines changed: 26 additions & 5 deletions

File tree

src/storage/git.rs

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,26 @@ use gix::prelude::*;
1919
use lru::LruCache;
2020
use std::collections::HashMap;
2121
use std::num::NonZeroUsize;
22+
use std::path::Path;
23+
use std::sync::atomic::{AtomicU64, Ordering};
2224

2325
const DEFAULT_CACHE_SIZE: NonZeroUsize = NonZeroUsize::new(1000).unwrap();
26+
static SYNC_TEMP_COUNTER: AtomicU64 = AtomicU64::new(0);
2427
use parking_lot::Mutex;
2528
use std::sync::Arc;
2629

2730
use super::{NodeStorage, StorageError};
2831

32+
fn sync_temp_path(dataset_dir: &Path, nanos: u64) -> std::path::PathBuf {
33+
let counter = SYNC_TEMP_COUNTER.fetch_add(1, Ordering::Relaxed);
34+
dataset_dir.join(format!(
35+
".prolly_hash_mappings.{}.{}.{}",
36+
std::process::id(),
37+
nanos,
38+
counter
39+
))
40+
}
41+
2942
/// Git-backed storage for ProllyTree nodes
3043
///
3144
/// This storage implementation uses Git blobs to store serialized ProllyNode instances.
@@ -309,11 +322,7 @@ impl<const N: usize> NodeStorage<N> for GitNodeStorage<N> {
309322
.duration_since(std::time::UNIX_EPOCH)
310323
.map(|d| d.as_nanos() as u64)
311324
.unwrap_or(0);
312-
let tmp = self.dataset_dir.join(format!(
313-
".prolly_hash_mappings.{}.{}",
314-
std::process::id(),
315-
nanos
316-
));
325+
let tmp = sync_temp_path(&self.dataset_dir, nanos);
317326
{
318327
use std::io::Write as _;
319328
let mut f = std::fs::File::create(&tmp).map_err(StorageError::Io)?;
@@ -440,6 +449,18 @@ mod tests {
440449
assert!(cached.is_some());
441450
}
442451

452+
#[test]
453+
fn sync_temp_path_uses_counter_for_same_timestamp() {
454+
let temp_dir = TempDir::new().unwrap();
455+
let first = sync_temp_path(temp_dir.path(), 123);
456+
let second = sync_temp_path(temp_dir.path(), 123);
457+
458+
assert_ne!(
459+
first, second,
460+
"same-process sync temp paths must not collide for the same timestamp"
461+
);
462+
}
463+
443464
#[test]
444465
fn clone_preserves_memory_only_tree_config() {
445466
let (temp_dir, repo) = create_test_repo();

0 commit comments

Comments
 (0)