Skip to content

Commit 9b03713

Browse files
committed
fix: collisions of newly written object's don't trigger collisions anymore. (#819)
It's solved by special-casing windows and assume that certain kinds of filesystem errors are the result of a collision (with some degree of concurrency/contention).
1 parent d372b24 commit 9b03713

File tree

2 files changed

+41
-1
lines changed

2 files changed

+41
-1
lines changed

gix-odb/src/store_impls/loose/write.rs

+12-1
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,18 @@ impl Store {
126126
}
127127
}
128128
let file = file.into_inner();
129-
file.persist(&object_path).map_err(|err| Error::Persist {
129+
let res = file.persist(&object_path);
130+
// On windows, we assume that such errors are due to its special filesystem semantics,
131+
// on any other platform that would be a legitimate error though.
132+
#[cfg(windows)]
133+
if let Err(err) = &res {
134+
if err.error.kind() == std::io::ErrorKind::PermissionDenied
135+
|| err.error.kind() == std::io::ErrorKind::AlreadyExists
136+
{
137+
return Ok(id);
138+
}
139+
}
140+
res.map_err(|err| Error::Persist {
130141
source: err,
131142
target: object_path,
132143
})?;

gix-odb/tests/odb/store/loose.rs

+29
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,35 @@ mod write {
7070
}
7171
Ok(())
7272
}
73+
74+
#[test]
75+
fn collisions_do_not_cause_failure() -> crate::Result {
76+
let dir = tempfile::tempdir()?;
77+
78+
fn write_empty_trees(dir: &std::path::Path) {
79+
let db = loose::Store::at(dir, gix_hash::Kind::Sha1);
80+
let empty_tree = gix_object::Tree::empty();
81+
for _ in 0..2 {
82+
let id = db.write(&empty_tree).expect("works");
83+
assert!(db.contains(id), "written objects are actually available");
84+
85+
let empty_blob = db.write_buf(gix_object::Kind::Blob, &[]).expect("works");
86+
assert!(db.contains(empty_blob), "written objects are actually available");
87+
let id = db
88+
.write_stream(gix_object::Kind::Blob, 0, &mut [].as_slice())
89+
.expect("works");
90+
assert_eq!(id, empty_blob);
91+
assert!(db.contains(empty_blob), "written objects are actually available");
92+
}
93+
}
94+
95+
gix_features::parallel::threads(|scope| {
96+
scope.spawn(|| write_empty_trees(dir.path()));
97+
scope.spawn(|| write_empty_trees(dir.path()));
98+
});
99+
100+
Ok(())
101+
}
73102
}
74103

75104
mod contains {

0 commit comments

Comments
 (0)