mirror of
https://github.com/rustfs/rustfs.git
synced 2026-07-26 08:18:18 +00:00
fix: resolve moved-value diagnostics (#4905)
Co-authored-by: heihutu <heihutu@gmail.com>
This commit is contained in:
@@ -26,10 +26,7 @@ use crate::disk::{
|
||||
error::{DiskError, Error, FileAccessDeniedWithContext, Result},
|
||||
error_conv::{to_access_error, to_file_error, to_unformatted_disk_error, to_volume_error},
|
||||
format::FormatV3,
|
||||
fs::{
|
||||
O_APPEND, O_CREATE, O_RDONLY, O_TRUNC, O_WRONLY, access, access_std, lstat, lstat_std, remove, remove_all_std,
|
||||
remove_std, rename,
|
||||
},
|
||||
fs::{O_APPEND, O_CREATE, O_RDONLY, O_TRUNC, O_WRONLY, access, lstat, lstat_std, remove, remove_all_std, remove_std, rename},
|
||||
os,
|
||||
os::{check_path_length, is_empty_dir, is_root_disk, rename_all, rename_all_ignore_missing_source},
|
||||
};
|
||||
@@ -101,7 +98,7 @@ fn inline_metadata_rollback_dir(version_id: Uuid, meta: &FileMeta) -> Uuid {
|
||||
fn remove_file_if_exists(path: &Path) -> std::io::Result<()> {
|
||||
match std::fs::remove_file(path) {
|
||||
Ok(()) => Ok(()),
|
||||
Err(err) if err.kind() == std::io::ErrorKind::NotFound => Ok(()),
|
||||
Err(err) if err.kind() == ErrorKind::NotFound => Ok(()),
|
||||
Err(err) => Err(err),
|
||||
}
|
||||
}
|
||||
@@ -109,7 +106,7 @@ fn remove_file_if_exists(path: &Path) -> std::io::Result<()> {
|
||||
fn remove_dir_all_if_exists(path: &Path) -> std::io::Result<()> {
|
||||
match std::fs::remove_dir_all(path) {
|
||||
Ok(()) => Ok(()),
|
||||
Err(err) if err.kind() == std::io::ErrorKind::NotFound => Ok(()),
|
||||
Err(err) if err.kind() == ErrorKind::NotFound => Ok(()),
|
||||
Err(err) => Err(err),
|
||||
}
|
||||
}
|
||||
@@ -121,7 +118,7 @@ fn rollback_committed_rename_std(
|
||||
) -> std::io::Result<()> {
|
||||
if let Some(old_data_dir) = rollback_data_dir {
|
||||
let Some(dst_parent) = dst_file_path.parent() else {
|
||||
return Err(std::io::Error::new(std::io::ErrorKind::InvalidInput, "missing object metadata parent"));
|
||||
return Err(std::io::Error::new(ErrorKind::InvalidInput, "missing object metadata parent"));
|
||||
};
|
||||
let backup_path = dst_parent.join(old_data_dir.to_string()).join(STORAGE_FORMAT_FILE_BACKUP);
|
||||
std::fs::rename(backup_path, dst_file_path)?;
|
||||
@@ -591,7 +588,7 @@ impl DurabilityMode {
|
||||
"strict" => Some(Self::Strict),
|
||||
"relaxed" => Some(Self::Relaxed),
|
||||
"none" => Some(Self::None),
|
||||
_ => Option::None,
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -799,7 +796,7 @@ pub(crate) mod bucket_durability {
|
||||
/// configured durability mode: their contents commit into user buckets and
|
||||
/// are exactly the writes the relaxed tiers exist for.
|
||||
fn is_scratch_volume(volume: &str) -> bool {
|
||||
for scratch in [super::RUSTFS_META_TMP_BUCKET, super::RUSTFS_META_MULTIPART_BUCKET] {
|
||||
for scratch in [RUSTFS_META_TMP_BUCKET, super::RUSTFS_META_MULTIPART_BUCKET] {
|
||||
if volume == scratch || volume.strip_prefix(scratch).is_some_and(|rest| rest.starts_with('/')) {
|
||||
return true;
|
||||
}
|
||||
@@ -816,7 +813,7 @@ fn is_system_critical_volume(volume: &str) -> bool {
|
||||
if is_scratch_volume(volume) {
|
||||
return false;
|
||||
}
|
||||
for meta in [super::RUSTFS_META_BUCKET, super::MIGRATING_META_BUCKET] {
|
||||
for meta in [RUSTFS_META_BUCKET, super::MIGRATING_META_BUCKET] {
|
||||
if volume == meta || volume.strip_prefix(meta).is_some_and(|rest| rest.starts_with('/')) {
|
||||
return true;
|
||||
}
|
||||
@@ -935,12 +932,12 @@ struct AlignedBuf {
|
||||
impl AlignedBuf {
|
||||
fn new(len: usize, align: usize) -> std::io::Result<Self> {
|
||||
debug_assert!(len > 0, "AlignedBuf must not be zero-sized");
|
||||
let layout = std::alloc::Layout::from_size_align(len, align)
|
||||
.map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidInput, e))?;
|
||||
let layout =
|
||||
std::alloc::Layout::from_size_align(len, align).map_err(|e| std::io::Error::new(ErrorKind::InvalidInput, e))?;
|
||||
// SAFETY: `layout` has non-zero size (callers guarantee len > 0) and a
|
||||
// valid power-of-two alignment enforced by Layout::from_size_align.
|
||||
let ptr = unsafe { std::alloc::alloc_zeroed(layout) };
|
||||
let ptr = std::ptr::NonNull::new(ptr).ok_or(std::io::ErrorKind::OutOfMemory)?;
|
||||
let ptr = std::ptr::NonNull::new(ptr).ok_or(ErrorKind::OutOfMemory)?;
|
||||
Ok(Self { ptr, len, layout })
|
||||
}
|
||||
|
||||
@@ -994,10 +991,9 @@ fn pread_direct_aligned(file_path: &Path, offset: u64, length: usize, state: &Di
|
||||
let align_u64 = align as u64;
|
||||
|
||||
let aligned_offset = offset - (offset % align_u64);
|
||||
let logical_start =
|
||||
usize::try_from(offset - aligned_offset).map_err(|_| std::io::Error::from(std::io::ErrorKind::InvalidInput))?;
|
||||
let logical_end = logical_start.checked_add(length).ok_or(std::io::ErrorKind::InvalidInput)?;
|
||||
let aligned_len = logical_end.checked_add(align - 1).ok_or(std::io::ErrorKind::InvalidInput)? / align * align;
|
||||
let logical_start = usize::try_from(offset - aligned_offset).map_err(|_| std::io::Error::from(ErrorKind::InvalidInput))?;
|
||||
let logical_end = logical_start.checked_add(length).ok_or(ErrorKind::InvalidInput)?;
|
||||
let aligned_len = logical_end.checked_add(align - 1).ok_or(ErrorKind::InvalidInput)? / align * align;
|
||||
|
||||
let mut buf = AlignedBuf::new(aligned_len, align)?;
|
||||
|
||||
@@ -1012,7 +1008,7 @@ fn pread_direct_aligned(file_path: &Path, offset: u64, length: usize, state: &Di
|
||||
filled += n;
|
||||
}
|
||||
if filled < logical_end {
|
||||
return Err(std::io::Error::new(std::io::ErrorKind::UnexpectedEof, "short O_DIRECT read"));
|
||||
return Err(std::io::Error::new(ErrorKind::UnexpectedEof, "short O_DIRECT read"));
|
||||
}
|
||||
|
||||
Ok(Bytes::copy_from_slice(&buf.as_slice()[logical_start..logical_end]))
|
||||
@@ -1094,10 +1090,7 @@ fn pwrite_all(file: &std::fs::File, mut buf: &[u8], mut offset: u64) -> std::io:
|
||||
while !buf.is_empty() {
|
||||
let n = file.write_at(buf, offset)?;
|
||||
if n == 0 {
|
||||
return Err(std::io::Error::new(
|
||||
std::io::ErrorKind::WriteZero,
|
||||
"O_DIRECT positioned write wrote 0 bytes",
|
||||
));
|
||||
return Err(std::io::Error::new(ErrorKind::WriteZero, "O_DIRECT positioned write wrote 0 bytes"));
|
||||
}
|
||||
buf = &buf[n..];
|
||||
offset += n as u64;
|
||||
@@ -2128,7 +2121,8 @@ impl LocalIoBackend for StdBackend {
|
||||
let access_check_start = metrics_enabled.then(StdInstant::now);
|
||||
let volume_dir = local_disk_bucket_path(&root, &volume_owned)?;
|
||||
if !skip_access_checks(&volume_owned) {
|
||||
access_std(&volume_dir).map_err(|e| DiskError::from(to_access_error(e, DiskError::VolumeAccessDenied)))?;
|
||||
crate::disk::fs::access_std(&volume_dir)
|
||||
.map_err(|e| DiskError::from(to_access_error(e, DiskError::VolumeAccessDenied)))?;
|
||||
}
|
||||
let access_check_duration = access_check_start.map_or(StdDuration::ZERO, |started_at| started_at.elapsed());
|
||||
|
||||
@@ -2948,7 +2942,8 @@ fn is_io_uring_unsupported(err: &std::io::Error) -> bool {
|
||||
fn resolve_uring_object_path(root: &Path, volume: &str, path: &str) -> Result<PathBuf> {
|
||||
let volume_dir = local_disk_bucket_path(root, volume)?;
|
||||
if !skip_access_checks(volume) {
|
||||
access_std(&volume_dir).map_err(|e| DiskError::from(to_access_error(e, DiskError::VolumeAccessDenied)))?;
|
||||
crate::disk::fs::access_std(&volume_dir)
|
||||
.map_err(|e| DiskError::from(to_access_error(e, DiskError::VolumeAccessDenied)))?;
|
||||
}
|
||||
let file_path = local_disk_object_path(root, volume, path)?;
|
||||
check_path_length(file_path.to_string_lossy().as_ref())?;
|
||||
@@ -3797,10 +3792,9 @@ impl LocalDisk {
|
||||
// rebuilding (see rustfs-heal); surface it so scanner
|
||||
// coordination, lock selection and admin/metrics see
|
||||
// the rebuild. Refreshed with this cache (~1s).
|
||||
let healing =
|
||||
tokio::fs::try_exists(root.join(super::RUSTFS_META_BUCKET).join(super::HEALING_MARKER_PATH))
|
||||
.await
|
||||
.unwrap_or(false);
|
||||
let healing = tokio::fs::try_exists(root.join(RUSTFS_META_BUCKET).join(super::HEALING_MARKER_PATH))
|
||||
.await
|
||||
.unwrap_or(false);
|
||||
let disk_info = DiskInfo {
|
||||
total: info.total,
|
||||
free: info.free,
|
||||
@@ -4780,8 +4774,8 @@ impl LocalDisk {
|
||||
let file_path = self.get_object_path(volume, path)?;
|
||||
check_path_length(file_path.to_string_lossy().as_ref())?;
|
||||
|
||||
let tmp_volume_dir = self.get_bucket_path(super::RUSTFS_META_TMP_BUCKET)?;
|
||||
let tmp_file_path = self.get_object_path(super::RUSTFS_META_TMP_BUCKET, Uuid::new_v4().to_string().as_str())?;
|
||||
let tmp_volume_dir = self.get_bucket_path(RUSTFS_META_TMP_BUCKET)?;
|
||||
let tmp_file_path = self.get_object_path(RUSTFS_META_TMP_BUCKET, Uuid::new_v4().to_string().as_str())?;
|
||||
|
||||
let durability = effective_durability(volume);
|
||||
|
||||
@@ -5641,7 +5635,7 @@ async fn read_file_metadata(p: impl AsRef<Path>) -> Result<Metadata> {
|
||||
fn skip_access_checks(p: impl AsRef<str>) -> bool {
|
||||
let vols = [
|
||||
RUSTFS_META_TMP_DELETED_BUCKET,
|
||||
super::RUSTFS_META_TMP_BUCKET,
|
||||
RUSTFS_META_TMP_BUCKET,
|
||||
super::RUSTFS_META_MULTIPART_BUCKET,
|
||||
RUSTFS_META_BUCKET,
|
||||
];
|
||||
@@ -5952,12 +5946,11 @@ impl DiskAPI for LocalDisk {
|
||||
);
|
||||
for (i, part) in fi.parts.iter().enumerate() {
|
||||
let checksum_info = erasure.get_checksum_info(part.number);
|
||||
let checksum_algo =
|
||||
if fi.uses_legacy_checksum && checksum_info.algorithm == rustfs_utils::HashAlgorithm::HighwayHash256S {
|
||||
rustfs_utils::HashAlgorithm::HighwayHash256SLegacy
|
||||
} else {
|
||||
checksum_info.algorithm
|
||||
};
|
||||
let checksum_algo = if fi.uses_legacy_checksum && checksum_info.algorithm == HashAlgorithm::HighwayHash256S {
|
||||
HashAlgorithm::HighwayHash256SLegacy
|
||||
} else {
|
||||
checksum_info.algorithm
|
||||
};
|
||||
let part_path = self.get_object_path(
|
||||
volume,
|
||||
path_join_buf(&[
|
||||
@@ -6985,7 +6978,7 @@ impl DiskAPI for LocalDisk {
|
||||
// Read existing xl.meta
|
||||
let has_dst_buf = match std::fs::read(&dst) {
|
||||
Ok(buf) => Some(Bytes::from(buf)),
|
||||
Err(e) if e.kind() == std::io::ErrorKind::NotFound => None,
|
||||
Err(e) if e.kind() == ErrorKind::NotFound => None,
|
||||
Err(e) => return Err(to_file_error(e)),
|
||||
};
|
||||
|
||||
@@ -7077,8 +7070,8 @@ impl DiskAPI for LocalDisk {
|
||||
|
||||
match std::fs::rename(&src, &dst) {
|
||||
Ok(()) => Ok(()),
|
||||
Err(err) if err.kind() == std::io::ErrorKind::NotFound && !src.exists() => Ok(()),
|
||||
Err(err) if err.kind() == std::io::ErrorKind::NotFound => {
|
||||
Err(err) if err.kind() == ErrorKind::NotFound && !src.exists() => Ok(()),
|
||||
Err(err) if err.kind() == ErrorKind::NotFound => {
|
||||
if let Some(parent) = dst.parent() {
|
||||
std::fs::create_dir_all(parent)?;
|
||||
}
|
||||
@@ -7126,7 +7119,7 @@ impl DiskAPI for LocalDisk {
|
||||
}
|
||||
}
|
||||
|
||||
Ok::<(Option<uuid::Uuid>, Option<Vec<u8>>, Option<OldCurrentSize>), std::io::Error>((
|
||||
Ok::<(Option<Uuid>, Option<Vec<u8>>, Option<OldCurrentSize>), std::io::Error>((
|
||||
rollback_data_dir,
|
||||
version_signature,
|
||||
old_current_size,
|
||||
@@ -8110,7 +8103,7 @@ mod test {
|
||||
|
||||
/// Crash-consistency harness for the rename_data commit sequence
|
||||
/// (rustfs/backlog#935 HP-14, test plan rustfs/backlog#896; hard rule from
|
||||
/// rustfs/backlog#878: "partial commit 后对象只能是旧版本或新版本,不能混合").
|
||||
/// rustfs/backlog#878: "After partial commit, the object can only be an old or new version; it cannot be mixed").
|
||||
///
|
||||
/// For every pre-commit crash point × durability tier, it seeds a committed
|
||||
/// object, stages a replacement, injects a hard power loss (no in-process
|
||||
@@ -8449,7 +8442,7 @@ mod test {
|
||||
/// Backdate a path's mtime so zero-expiry cleanup tests classify it as
|
||||
/// stale deterministically, instead of sleeping and hoping the filesystem
|
||||
/// timestamp granularity (or a backward wall-clock step) cooperates.
|
||||
fn backdate_mtime(path: &std::path::Path, age: Duration) {
|
||||
fn backdate_mtime(path: &Path, age: Duration) {
|
||||
use std::fs::{File, FileTimes};
|
||||
let mtime = std::time::SystemTime::now() - age;
|
||||
File::open(path)
|
||||
@@ -8858,17 +8851,13 @@ mod test {
|
||||
async fn blocking_scan_writer_keeps_flush_and_shutdown_pending() {
|
||||
let mut flush_writer = BlockingScanWriter { entered_tx: None };
|
||||
assert!(
|
||||
tokio::time::timeout(Duration::from_millis(10), flush_writer.flush())
|
||||
.await
|
||||
.is_err(),
|
||||
timeout(Duration::from_millis(10), flush_writer.flush()).await.is_err(),
|
||||
"blocking scan writer flush should stay pending"
|
||||
);
|
||||
|
||||
let mut shutdown_writer = BlockingScanWriter { entered_tx: None };
|
||||
assert!(
|
||||
tokio::time::timeout(Duration::from_millis(10), shutdown_writer.shutdown())
|
||||
.await
|
||||
.is_err(),
|
||||
timeout(Duration::from_millis(10), shutdown_writer.shutdown()).await.is_err(),
|
||||
"blocking scan writer shutdown should stay pending"
|
||||
);
|
||||
}
|
||||
@@ -8877,15 +8866,11 @@ mod test {
|
||||
/// consumer (quorum merge, a lagging peer drive).
|
||||
struct SlowWriter {
|
||||
delay: Duration,
|
||||
sleep: Option<std::pin::Pin<Box<Sleep>>>,
|
||||
sleep: Option<Pin<Box<Sleep>>>,
|
||||
}
|
||||
|
||||
impl AsyncWrite for SlowWriter {
|
||||
fn poll_write(
|
||||
mut self: std::pin::Pin<&mut Self>,
|
||||
cx: &mut std::task::Context<'_>,
|
||||
buf: &[u8],
|
||||
) -> std::task::Poll<std::io::Result<usize>> {
|
||||
fn poll_write(mut self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8]) -> Poll<io::Result<usize>> {
|
||||
if self.sleep.is_none() {
|
||||
let delay = self.delay;
|
||||
self.sleep = Some(Box::pin(tokio::time::sleep(delay)));
|
||||
@@ -8893,23 +8878,20 @@ mod test {
|
||||
|
||||
let sleep = self.sleep.as_mut().expect("sleep was just installed");
|
||||
match sleep.as_mut().poll(cx) {
|
||||
std::task::Poll::Ready(()) => {
|
||||
Poll::Ready(()) => {
|
||||
self.sleep = None;
|
||||
std::task::Poll::Ready(Ok(buf.len()))
|
||||
Poll::Ready(Ok(buf.len()))
|
||||
}
|
||||
std::task::Poll::Pending => std::task::Poll::Pending,
|
||||
Poll::Pending => Poll::Pending,
|
||||
}
|
||||
}
|
||||
|
||||
fn poll_flush(self: std::pin::Pin<&mut Self>, _cx: &mut std::task::Context<'_>) -> std::task::Poll<std::io::Result<()>> {
|
||||
std::task::Poll::Ready(Ok(()))
|
||||
fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
|
||||
fn poll_shutdown(
|
||||
self: std::pin::Pin<&mut Self>,
|
||||
_cx: &mut std::task::Context<'_>,
|
||||
) -> std::task::Poll<std::io::Result<()>> {
|
||||
std::task::Poll::Ready(Ok(()))
|
||||
fn poll_shutdown(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9605,14 +9587,14 @@ mod test {
|
||||
bucket_durability::set(super::super::RUSTFS_META_MULTIPART_BUCKET, Some(DurabilityMode::Relaxed));
|
||||
bucket_durability::set("", Some(DurabilityMode::Relaxed));
|
||||
|
||||
assert_eq!(bucket_durability::lookup(RUSTFS_META_BUCKET), Option::None);
|
||||
assert_eq!(bucket_durability::lookup(RUSTFS_META_TMP_BUCKET), Option::None);
|
||||
assert_eq!(bucket_durability::lookup(RUSTFS_META_BUCKET), None);
|
||||
assert_eq!(bucket_durability::lookup(RUSTFS_META_TMP_BUCKET), None);
|
||||
assert_eq!(effective_durability(RUSTFS_META_BUCKET), DurabilityMode::Strict);
|
||||
|
||||
// The legacy full-off tier is process-wide only: registering it per
|
||||
// bucket is dropped, not stored.
|
||||
bucket_durability::set("hp5b-legacy-refused", Some(DurabilityMode::LegacyOff));
|
||||
assert_eq!(bucket_durability::lookup("hp5b-legacy-refused"), Option::None);
|
||||
assert_eq!(bucket_durability::lookup("hp5b-legacy-refused"), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -11071,7 +11053,7 @@ mod test {
|
||||
|
||||
let vols = [
|
||||
RUSTFS_META_TMP_DELETED_BUCKET,
|
||||
super::super::RUSTFS_META_TMP_BUCKET,
|
||||
RUSTFS_META_TMP_BUCKET,
|
||||
super::super::RUSTFS_META_MULTIPART_BUCKET,
|
||||
RUSTFS_META_BUCKET,
|
||||
];
|
||||
@@ -11110,7 +11092,7 @@ mod test {
|
||||
let mut reader = StallTimeoutReader::new(PendingTestReader, Duration::ZERO);
|
||||
let mut buf = [0; 1];
|
||||
|
||||
let result = tokio::time::timeout(Duration::from_millis(10), reader.read(&mut buf)).await;
|
||||
let result = timeout(Duration::from_millis(10), reader.read(&mut buf)).await;
|
||||
|
||||
assert!(result.is_err(), "zero timeout must leave stalled reads pending instead of failing");
|
||||
}
|
||||
@@ -11240,10 +11222,10 @@ mod test {
|
||||
|
||||
#[tokio::test(start_paused = true)]
|
||||
async fn cleanup_loop_interval_does_not_tick_immediately() {
|
||||
let start_at = tokio::time::Instant::now() + DELETED_OBJECTS_CLEANUP_INTERVAL;
|
||||
let start_at = Instant::now() + DELETED_OBJECTS_CLEANUP_INTERVAL;
|
||||
let mut interval = interval_at(start_at, DELETED_OBJECTS_CLEANUP_INTERVAL);
|
||||
|
||||
assert!(tokio::time::timeout(Duration::from_secs(1), interval.tick()).await.is_err());
|
||||
assert!(timeout(Duration::from_secs(1), interval.tick()).await.is_err());
|
||||
|
||||
tokio::time::advance(DELETED_OBJECTS_CLEANUP_INTERVAL).await;
|
||||
interval.tick().await;
|
||||
@@ -11291,26 +11273,16 @@ mod test {
|
||||
struct BrokenPipeWriter;
|
||||
|
||||
impl AsyncWrite for BrokenPipeWriter {
|
||||
fn poll_write(
|
||||
self: std::pin::Pin<&mut Self>,
|
||||
_cx: &mut std::task::Context<'_>,
|
||||
_buf: &[u8],
|
||||
) -> std::task::Poll<std::io::Result<usize>> {
|
||||
std::task::Poll::Ready(Err(std::io::Error::new(std::io::ErrorKind::BrokenPipe, "closed")))
|
||||
fn poll_write(self: Pin<&mut Self>, _cx: &mut Context<'_>, _buf: &[u8]) -> Poll<io::Result<usize>> {
|
||||
Poll::Ready(Err(io::Error::new(ErrorKind::BrokenPipe, "closed")))
|
||||
}
|
||||
|
||||
fn poll_flush(
|
||||
self: std::pin::Pin<&mut Self>,
|
||||
_cx: &mut std::task::Context<'_>,
|
||||
) -> std::task::Poll<std::io::Result<()>> {
|
||||
std::task::Poll::Ready(Ok(()))
|
||||
fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
|
||||
fn poll_shutdown(
|
||||
self: std::pin::Pin<&mut Self>,
|
||||
_cx: &mut std::task::Context<'_>,
|
||||
) -> std::task::Poll<std::io::Result<()>> {
|
||||
std::task::Poll::Ready(Ok(()))
|
||||
fn poll_shutdown(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
|
||||
Poll::Ready(Ok(()))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12442,7 +12414,7 @@ mod test {
|
||||
fs::set_permissions(&meta_path, Permissions::from_mode(0o000))
|
||||
.await
|
||||
.expect("operation should succeed");
|
||||
if fs::File::open(&meta_path).await.is_ok() {
|
||||
if File::open(&meta_path).await.is_ok() {
|
||||
fs::set_permissions(&meta_path, original_permissions)
|
||||
.await
|
||||
.expect("operation should succeed");
|
||||
@@ -12977,7 +12949,7 @@ mod test {
|
||||
// It only checks length and platform-specific special characters
|
||||
// System volume names are valid according to the current implementation
|
||||
assert!(LocalDisk::is_valid_volname(RUSTFS_META_BUCKET));
|
||||
assert!(LocalDisk::is_valid_volname(super::super::RUSTFS_META_TMP_BUCKET));
|
||||
assert!(LocalDisk::is_valid_volname(RUSTFS_META_TMP_BUCKET));
|
||||
|
||||
// Testing platform-specific behavior for special characters
|
||||
#[cfg(windows)]
|
||||
@@ -13321,24 +13293,20 @@ mod test {
|
||||
|
||||
#[cfg(unix)]
|
||||
{
|
||||
for (kind, expected) in [("minor", 1), ("major", 2)] {
|
||||
for (kind, expected) in [("minor", 1), ("major", 2)].iter().copied() {
|
||||
let labels = [("path", "local_test"), ("stage", "mmap_map"), ("kind", kind)];
|
||||
assert_eq!(
|
||||
recorder.counter_value(
|
||||
METRIC_GET_OBJECT_MMAP_PAGE_FAULTS_TOTAL,
|
||||
&[("path", "local_test"), ("stage", "mmap_map"), ("kind", kind)]
|
||||
),
|
||||
recorder.counter_value(METRIC_GET_OBJECT_MMAP_PAGE_FAULTS_TOTAL, &labels),
|
||||
expected,
|
||||
"zero deltas must not emit and positive {kind} deltas must accumulate exactly"
|
||||
"zero deltas must not emit and positive mmap page fault deltas must accumulate exactly"
|
||||
);
|
||||
}
|
||||
for (kind, expected) in [("minor", 3), ("major", 4)] {
|
||||
for (kind, expected) in [("minor", 3), ("major", 4)].iter().copied() {
|
||||
let labels = [("path", "local_test"), ("stage", "direct_read_copy"), ("kind", kind)];
|
||||
assert_eq!(
|
||||
recorder.counter_value(
|
||||
METRIC_GET_OBJECT_DIRECT_READ_PAGE_FAULTS_TOTAL,
|
||||
&[("path", "local_test"), ("stage", "direct_read_copy"), ("kind", kind)]
|
||||
),
|
||||
recorder.counter_value(METRIC_GET_OBJECT_DIRECT_READ_PAGE_FAULTS_TOTAL, &labels),
|
||||
expected,
|
||||
"zero deltas must not emit and positive {kind} deltas must accumulate exactly"
|
||||
"zero deltas must not emit and positive direct-read page fault deltas must accumulate exactly"
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -13553,15 +13521,15 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_is_bitrot_size_mismatch_error_only_matches_target_message() {
|
||||
assert!(is_bitrot_size_mismatch_error(&std::io::Error::other("bitrot shard file size mismatch")));
|
||||
assert!(!is_bitrot_size_mismatch_error(&std::io::Error::other("bitrot hash mismatch")));
|
||||
assert!(is_bitrot_size_mismatch_error(&io::Error::other("bitrot shard file size mismatch")));
|
||||
assert!(!is_bitrot_size_mismatch_error(&io::Error::other("bitrot hash mismatch")));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_bitrot_verification_error_matches_hash_and_size_mismatch() {
|
||||
assert!(is_bitrot_verification_error(&std::io::Error::other("bitrot shard file size mismatch")));
|
||||
assert!(is_bitrot_verification_error(&std::io::Error::other("bitrot hash mismatch")));
|
||||
assert!(!is_bitrot_verification_error(&std::io::Error::other("unrelated io failure")));
|
||||
assert!(is_bitrot_verification_error(&io::Error::other("bitrot shard file size mismatch")));
|
||||
assert!(is_bitrot_verification_error(&io::Error::other("bitrot hash mismatch")));
|
||||
assert!(!is_bitrot_verification_error(&io::Error::other("unrelated io failure")));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
@@ -13600,7 +13568,7 @@ mod test {
|
||||
..Default::default()
|
||||
}];
|
||||
|
||||
let mut writer = BitrotWriter::new(std::io::Cursor::new(Vec::new()), file_info.erasure.shard_size(), checksum_algo);
|
||||
let mut writer = BitrotWriter::new(io::Cursor::new(Vec::new()), file_info.erasure.shard_size(), checksum_algo);
|
||||
writer
|
||||
.write(&payload)
|
||||
.await
|
||||
@@ -13667,7 +13635,7 @@ mod test {
|
||||
} else {
|
||||
HashAlgorithm::HighwayHash256S
|
||||
};
|
||||
let mut writer = BitrotWriter::new(std::io::Cursor::new(Vec::new()), codec_erasure.shard_size(), checksum_algo);
|
||||
let mut writer = BitrotWriter::new(io::Cursor::new(Vec::new()), codec_erasure.shard_size(), checksum_algo);
|
||||
writer.write(&payload[..8]).await.expect("first shard block should encode");
|
||||
writer.write(&payload[8..]).await.expect("final shard block should encode");
|
||||
writer.shutdown().await.expect("bitrot writer should flush test payload");
|
||||
@@ -14524,7 +14492,7 @@ mod test {
|
||||
// SAFETY: `map.as_ptr()` is page-aligned and `len` bytes long; `vec` has
|
||||
// one byte per page of that range, which is what mincore writes.
|
||||
let rc = unsafe { libc::mincore(map.as_ptr() as *mut libc::c_void, len, vec.as_mut_ptr()) };
|
||||
assert_eq!(rc, 0, "mincore failed: {}", std::io::Error::last_os_error());
|
||||
assert_eq!(rc, 0, "mincore failed: {}", io::Error::last_os_error());
|
||||
vec.iter().filter(|b| *b & 1 == 1).count()
|
||||
}
|
||||
|
||||
|
||||
@@ -157,8 +157,8 @@ impl LocalKmsClient {
|
||||
Ok(salt)
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
async fn set_file_permissions(path: &std::path::Path, permissions: Option<u32>) -> Result<()> {
|
||||
#[cfg(unix)]
|
||||
if let Some(mode) = permissions {
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
|
||||
@@ -166,7 +166,11 @@ impl LocalKmsClient {
|
||||
fs::set_permissions(path, perms).await?;
|
||||
}
|
||||
|
||||
let _ = permissions;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(not(unix))]
|
||||
async fn set_file_permissions(_path: &std::path::Path, _permissions: Option<u32>) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user