Compare commits

...

1 Commits

Author SHA1 Message Date
唐小鸭 9dff5b6aea fix(windows): release rebuild source pins and align test fixtures
Release the multipart source directory pin as soon as the upload head is
decoded during online index rebuild. On Windows the pin denies delete
sharing, so keeping it while indexing made a concurrent abort fail with a
sharing violation.

Align three test fixtures with Windows path and handle semantics:
- heal bucket pass targets use the endpoint string form, matching
  production disk endpoint identity;
- scanner erasure probe injection keys are normalized with path_join_buf
  so they match the scanner's lookup keys;
- the targets queue budget test changes mtime through a writable handle,
  which Windows requires.
2026-11-09 11:26:04 +08:00
4 changed files with 21 additions and 3 deletions
@@ -192,6 +192,10 @@ impl RebuildCursor {
Err(error) if error.kind() == io::ErrorKind::NotFound => continue,
Err(error) => return Err(error),
};
// The head is decoded; release the source pin before indexing. On
// Windows the pin denies delete sharing, so holding it would make a
// concurrent abort of this upload fail with a sharing violation.
drop(source);
let source_root = relative
.file_name()
.and_then(|name| name.to_str())
+7 -1
View File
@@ -385,9 +385,15 @@ mod tests {
.is_err(),
"a stale worker cannot mutate a recreated bucket"
);
// Name targets as the store's endpoints render them (`C:/...` on Windows),
// not as raw OS paths.
let targets = directories
.iter()
.map(|dir| dir.path().to_string_lossy().into_owned())
.map(|dir| {
crate::heal::Endpoint::try_from(dir.path().to_str().expect("UTF-8 temp disk path"))
.expect("temp disk endpoint")
.to_string()
})
.collect::<Vec<_>>();
assert!(
storage
@@ -19,7 +19,9 @@ pub(in crate::scanner_folder) struct OrderedDirectory(String);
impl OrderedDirectory {
fn new(path: &std::path::Path) -> Self {
let path = path.to_string_lossy().into_owned();
// Key the probe by the cleaned form the scanner opens; on Windows a joined
// `C:\root\bucket/object` would otherwise never match `C:/root/bucket/object`.
let path = rustfs_utils::path::path_join_buf(&[&path.to_string_lossy()]);
ORDERED_DIRECTORIES
.lock()
.expect("ordered directory registry")
+7 -1
View File
@@ -1456,7 +1456,13 @@ mod tests {
store.put_failed_raw("failed-event", &[4; 16]).unwrap();
assert_eq!(store.stored_bytes.load(Ordering::SeqCst), 48);
let failed = store.failed_dir().join("failed-event");
File::open(&failed).unwrap().set_modified(UNIX_EPOCH).unwrap();
// Windows needs write-attribute access on the handle to change mtime.
std::fs::OpenOptions::new()
.write(true)
.open(&failed)
.unwrap()
.set_modified(UNIX_EPOCH)
.unwrap();
assert_eq!(store.prune_failed_store().unwrap(), 1);
assert_eq!(store.stored_bytes.load(Ordering::SeqCst), 32);
std::fs::create_dir(store.failed_dir().join("cannot-replace-directory")).unwrap();