mc test ok

This commit is contained in:
weisd
2025-06-06 16:15:26 +08:00
parent 3dacde092c
commit c589972fa7
55 changed files with 5053 additions and 17559 deletions
+719 -719
View File
File diff suppressed because it is too large Load Diff
+5 -1
View File
@@ -34,13 +34,17 @@ impl BucketMetadataError {
impl From<BucketMetadataError> for Error {
fn from(e: BucketMetadataError) -> Self {
Error::other(e)
match e {
BucketMetadataError::BucketPolicyNotFound => Error::BucketPolicyNotFound,
_ => Error::other(e),
}
}
}
impl From<Error> for BucketMetadataError {
fn from(e: Error) -> Self {
match e {
Error::BucketPolicyNotFound => BucketMetadataError::BucketPolicyNotFound,
Error::Io(e) => e.into(),
_ => BucketMetadataError::other(e),
}
+17 -17
View File
@@ -1,29 +1,29 @@
use super::error::{Error, Result};
use super::os::{is_root_disk, rename_all};
use super::{endpoint::Endpoint, error::DiskError, format::FormatV3};
use super::{
os, CheckPartsResp, DeleteOptions, DiskAPI, DiskInfo, DiskInfoOptions, DiskLocation, DiskMetrics, FileInfoVersions, Info,
ReadMultipleReq, ReadMultipleResp, ReadOptions, RenameDataResp, UpdateMetadataOpts, VolumeInfo, WalkDirOptions,
BUCKET_META_PREFIX, RUSTFS_META_BUCKET, STORAGE_FORMAT_FILE_BACKUP,
BUCKET_META_PREFIX, CheckPartsResp, DeleteOptions, DiskAPI, DiskInfo, DiskInfoOptions, DiskLocation, DiskMetrics,
FileInfoVersions, Info, RUSTFS_META_BUCKET, ReadMultipleReq, ReadMultipleResp, ReadOptions, RenameDataResp,
STORAGE_FORMAT_FILE_BACKUP, UpdateMetadataOpts, VolumeInfo, WalkDirOptions, os,
};
use super::{endpoint::Endpoint, error::DiskError, format::FormatV3};
use crate::bucket::metadata_sys::{self};
use crate::bucket::versioning::VersioningApi;
use crate::bucket::versioning_sys::BucketVersioningSys;
use crate::disk::STORAGE_FORMAT_FILE;
use crate::disk::error::FileAccessDeniedWithContext;
use crate::disk::error_conv::{to_access_error, to_file_error, to_unformatted_disk_error, to_volume_error};
use crate::disk::fs::{
access, lstat, lstat_std, remove, remove_all_std, remove_std, rename, O_APPEND, O_CREATE, O_RDONLY, O_TRUNC, O_WRONLY,
O_APPEND, O_CREATE, O_RDONLY, O_TRUNC, O_WRONLY, access, lstat, lstat_std, remove, remove_all_std, remove_std, rename,
};
use crate::disk::os::{check_path_length, is_empty_dir};
use crate::disk::STORAGE_FORMAT_FILE;
use crate::disk::{
conv_part_err_to_int, CHECK_PART_FILE_CORRUPT, CHECK_PART_FILE_NOT_FOUND, CHECK_PART_SUCCESS, CHECK_PART_UNKNOWN,
CHECK_PART_VOLUME_NOT_FOUND,
CHECK_PART_FILE_CORRUPT, CHECK_PART_FILE_NOT_FOUND, CHECK_PART_SUCCESS, CHECK_PART_UNKNOWN, CHECK_PART_VOLUME_NOT_FOUND,
conv_part_err_to_int,
};
use crate::global::{GLOBAL_IsErasureSD, GLOBAL_RootDiskThreshold};
use crate::heal::data_scanner::{
lc_has_active_rules, rep_has_active_rules, scan_data_folder, ScannerItem, ShouldSleepFn, SizeSummary,
ScannerItem, ShouldSleepFn, SizeSummary, lc_has_active_rules, rep_has_active_rules, scan_data_folder,
};
use crate::heal::data_scanner_metric::{ScannerMetric, ScannerMetrics};
use crate::heal::data_usage_cache::{DataUsageCache, DataUsageEntry};
@@ -35,23 +35,23 @@ use crate::new_object_layer_fn;
use crate::store_api::{ObjectInfo, StorageAPI};
use crate::utils::os::get_info;
use crate::utils::path::{
clean, decode_dir_object, encode_dir_object, has_suffix, path_join, path_join_buf, GLOBAL_DIR_SUFFIX,
GLOBAL_DIR_SUFFIX_WITH_SLASH, SLASH_SEPARATOR,
GLOBAL_DIR_SUFFIX, GLOBAL_DIR_SUFFIX_WITH_SLASH, SLASH_SEPARATOR, clean, decode_dir_object, encode_dir_object, has_suffix,
path_join, path_join_buf,
};
use common::defer;
use path_absolutize::Absolutize;
use rustfs_filemeta::{
get_file_info, read_xl_meta_no_data, Cache, FileInfo, FileInfoOpts, FileMeta, MetaCacheEntry, MetacacheWriter, Opts,
RawFileInfo, UpdateFn,
Cache, FileInfo, FileInfoOpts, FileMeta, MetaCacheEntry, MetacacheWriter, Opts, RawFileInfo, UpdateFn, get_file_info,
read_xl_meta_no_data,
};
use rustfs_rio::{bitrot_verify, Reader};
use rustfs_rio::{Reader, bitrot_verify};
use rustfs_utils::HashAlgorithm;
use std::collections::{HashMap, HashSet};
use std::fmt::Debug;
use std::io::SeekFrom;
use std::sync::atomic::{AtomicU32, Ordering};
use std::sync::Arc;
use std::sync::atomic::{AtomicU32, Ordering};
use std::time::{Duration, SystemTime};
use std::{
fs::Metadata,
@@ -60,8 +60,8 @@ use std::{
use time::OffsetDateTime;
use tokio::fs::{self, File};
use tokio::io::{AsyncReadExt, AsyncSeekExt, AsyncWrite, AsyncWriteExt, ErrorKind};
use tokio::sync::mpsc::Sender;
use tokio::sync::RwLock;
use tokio::sync::mpsc::Sender;
use tracing::{debug, error, info, warn};
use uuid::Uuid;
@@ -1550,7 +1550,7 @@ impl DiskAPI for LocalDisk {
Ok(())
}
#[tracing::instrument(level = "debug", skip(self))]
#[tracing::instrument(level = "debug", skip(self, fi))]
async fn rename_data(
&self,
src_volume: &str,
+13 -13
View File
@@ -1,8 +1,8 @@
use crate::utils::ellipses::*;
use common::error::{Error, Result};
use serde::Deserialize;
use std::collections::HashSet;
use std::env;
use std::io::{Error, Result};
use tracing::debug;
/// Supported set sizes this is used to find the optimal
@@ -89,7 +89,7 @@ pub struct DisksLayout {
impl DisksLayout {
pub fn from_volumes<T: AsRef<str>>(args: &[T]) -> Result<Self> {
if args.is_empty() {
return Err(Error::from_string("Invalid argument"));
return Err(Error::other("Invalid argument"));
}
let is_ellipses = args.iter().any(|v| has_ellipses(&[v]));
@@ -98,7 +98,7 @@ impl DisksLayout {
debug!("{} not set use default:0, {:?}", ENV_RUSTFS_ERASURE_SET_DRIVE_COUNT, err);
"0".to_string()
});
let set_drive_count: usize = set_drive_count_env.parse()?;
let set_drive_count: usize = set_drive_count_env.parse().map_err(Error::other)?;
// None of the args have ellipses use the old style.
if !is_ellipses {
@@ -116,7 +116,7 @@ impl DisksLayout {
let mut layout = Vec::with_capacity(args.len());
for arg in args.iter() {
if !has_ellipses(&[arg]) && args.len() > 1 {
return Err(Error::from_string(
return Err(Error::other(
"all args must have ellipses for pool expansion (Invalid arguments specified)",
));
}
@@ -189,7 +189,7 @@ fn get_all_sets<T: AsRef<str>>(set_drive_count: usize, is_ellipses: bool, args:
for args in set_args.iter() {
for arg in args {
if unique_args.contains(arg) {
return Err(Error::from_string(format!("Input args {} has duplicate ellipses", arg)));
return Err(Error::other(format!("Input args {} has duplicate ellipses", arg)));
}
unique_args.insert(arg);
}
@@ -245,7 +245,7 @@ impl EndpointSet {
}
}
pub fn from_volumes<T: AsRef<str>>(args: &[T], set_drive_count: usize) -> Result<Self, Error> {
pub fn from_volumes<T: AsRef<str>>(args: &[T], set_drive_count: usize) -> Result<Self> {
let mut arg_patterns = Vec::with_capacity(args.len());
for arg in args {
arg_patterns.push(find_ellipses_patterns(arg.as_ref())?);
@@ -377,20 +377,20 @@ fn get_set_indexes<T: AsRef<str>>(
arg_patterns: &[ArgPattern],
) -> Result<Vec<Vec<usize>>> {
if args.is_empty() || total_sizes.is_empty() {
return Err(Error::from_string("Invalid argument"));
return Err(Error::other("Invalid argument"));
}
for &size in total_sizes {
// Check if total_sizes has minimum range upto set_size
if size < SET_SIZES[0] || size < set_drive_count {
return Err(Error::from_string(format!("Incorrect number of endpoints provided, size {}", size)));
return Err(Error::other(format!("Incorrect number of endpoints provided, size {}", size)));
}
}
let common_size = get_divisible_size(total_sizes);
let mut set_counts = possible_set_counts(common_size);
if set_counts.is_empty() {
return Err(Error::from_string(format!(
return Err(Error::other(format!(
"Incorrect number of endpoints provided, number of drives {} is not divisible by any supported erasure set sizes {}",
common_size, 0
)));
@@ -399,7 +399,7 @@ fn get_set_indexes<T: AsRef<str>>(
// Returns possible set counts with symmetry.
set_counts = possible_set_counts_with_symmetry(&set_counts, arg_patterns);
if set_counts.is_empty() {
return Err(Error::from_string("No symmetric distribution detected with input endpoints provided"));
return Err(Error::other("No symmetric distribution detected with input endpoints provided"));
}
let set_size = {
@@ -407,7 +407,7 @@ fn get_set_indexes<T: AsRef<str>>(
let has_set_drive_count = set_counts.contains(&set_drive_count);
if !has_set_drive_count {
return Err(Error::from_string(format!(
return Err(Error::other(format!(
"Invalid set drive count {}. Acceptable values for {:?} number drives are {:?}",
set_drive_count, common_size, &set_counts
)));
@@ -416,7 +416,7 @@ fn get_set_indexes<T: AsRef<str>>(
} else {
set_counts = possible_set_counts_with_symmetry(&set_counts, arg_patterns);
if set_counts.is_empty() {
return Err(Error::from_string(format!(
return Err(Error::other(format!(
"No symmetric distribution detected with input endpoints , drives {} cannot be spread symmetrically by any supported erasure set sizes {:?}",
common_size, &set_counts
)));
@@ -427,7 +427,7 @@ fn get_set_indexes<T: AsRef<str>>(
};
if !is_valid_set_size(set_size) {
return Err(Error::from_string("Incorrect number of endpoints provided3"));
return Err(Error::other("Incorrect number of endpoints provided3"));
}
Ok(total_sizes
+28 -31
View File
@@ -6,9 +6,9 @@ use crate::{
global::global_rustfs_port,
utils::net::{self, XHost},
};
use common::error::{Error, Result};
use std::io::{Error, Result};
use std::{
collections::{hash_map::Entry, HashMap, HashSet},
collections::{HashMap, HashSet, hash_map::Entry},
net::IpAddr,
};
@@ -76,7 +76,7 @@ impl<T: AsRef<str>> TryFrom<&[T]> for Endpoints {
for (i, arg) in args.iter().enumerate() {
let endpoint = match Endpoint::try_from(arg.as_ref()) {
Ok(ep) => ep,
Err(e) => return Err(Error::from_string(format!("'{}': {}", arg.as_ref(), e))),
Err(e) => return Err(Error::other(format!("'{}': {}", arg.as_ref(), e))),
};
// All endpoints have to be same type and scheme if applicable.
@@ -84,15 +84,15 @@ impl<T: AsRef<str>> TryFrom<&[T]> for Endpoints {
endpoint_type = Some(endpoint.get_type());
schema = Some(endpoint.url.scheme().to_owned());
} else if Some(endpoint.get_type()) != endpoint_type {
return Err(Error::from_string("mixed style endpoints are not supported"));
return Err(Error::other("mixed style endpoints are not supported"));
} else if Some(endpoint.url.scheme()) != schema.as_deref() {
return Err(Error::from_string("mixed scheme is not supported"));
return Err(Error::other("mixed scheme is not supported"));
}
// Check for duplicate endpoints.
let endpoint_str = endpoint.to_string();
if uniq_set.contains(&endpoint_str) {
return Err(Error::from_string("duplicate endpoints found"));
return Err(Error::other("duplicate endpoints found"));
}
uniq_set.insert(endpoint_str);
@@ -156,7 +156,7 @@ impl PoolEndpointList {
/// hostnames and discovers those are local or remote.
fn create_pool_endpoints(server_addr: &str, disks_layout: &DisksLayout) -> Result<Self> {
if disks_layout.is_empty_layout() {
return Err(Error::from_string("invalid number of endpoints"));
return Err(Error::other("invalid number of endpoints"));
}
let server_addr = net::check_local_server_addr(server_addr)?;
@@ -167,7 +167,7 @@ impl PoolEndpointList {
endpoint.update_is_local(server_addr.port())?;
if endpoint.get_type() != EndpointType::Path {
return Err(Error::from_string("use path style endpoint for single node setup"));
return Err(Error::other("use path style endpoint for single node setup"));
}
endpoint.set_pool_index(0);
@@ -201,7 +201,7 @@ impl PoolEndpointList {
}
if endpoints.as_ref().is_empty() {
return Err(Error::from_string("invalid number of endpoints"));
return Err(Error::other("invalid number of endpoints"));
}
pool_endpoints.push(endpoints);
@@ -227,15 +227,14 @@ impl PoolEndpointList {
let host = ep.url.host().unwrap();
let host_ip_set = host_ip_cache.entry(host.clone()).or_insert({
net::get_host_ip(host.clone())
.map_err(|e| Error::from_string(format!("host '{}' cannot resolve: {}", host, e)))?
net::get_host_ip(host.clone()).map_err(|e| Error::other(format!("host '{}' cannot resolve: {}", host, e)))?
});
let path = ep.get_file_path();
match path_ip_map.entry(path) {
Entry::Occupied(mut e) => {
if e.get().intersection(host_ip_set).count() > 0 {
return Err(Error::from_string(format!(
return Err(Error::other(format!(
"same path '{}' can not be served by different port on same address",
path
)));
@@ -257,7 +256,7 @@ impl PoolEndpointList {
let path = ep.get_file_path();
if local_path_set.contains(path) {
return Err(Error::from_string(format!(
return Err(Error::other(format!(
"path '{}' cannot be served by different address on same server",
path
)));
@@ -285,7 +284,7 @@ impl PoolEndpointList {
// If all endpoints have same port number, Just treat it as local erasure setup
// using URL style endpoints.
if local_port_set.len() == 1 && local_server_host_set.len() > 1 {
return Err(Error::from_string("all local endpoints should not have different hostnames/ips"));
return Err(Error::other("all local endpoints should not have different hostnames/ips"));
}
}
@@ -453,7 +452,7 @@ impl EndpointServerPools {
/// both ellipses and without ellipses transparently.
pub fn create_server_endpoints(server_addr: &str, disks_layout: &DisksLayout) -> Result<(EndpointServerPools, SetupType)> {
if disks_layout.pools.is_empty() {
return Err(Error::from_string("Invalid arguments specified"));
return Err(Error::other("Invalid arguments specified"));
}
let pool_eps = PoolEndpointList::create_pool_endpoints(server_addr, disks_layout)?;
@@ -490,7 +489,7 @@ impl EndpointServerPools {
for ep in eps.endpoints.as_ref() {
if exits.contains(&ep.to_string()) {
return Err(Error::from_string("duplicate endpoints found"));
return Err(Error::other("duplicate endpoints found"));
}
}
@@ -664,8 +663,8 @@ mod test {
None,
6,
),
(vec!["d1", "d2", "d3", "d1"], Some(Error::from_string("duplicate endpoints found")), 7),
(vec!["d1", "d2", "d3", "./d1"], Some(Error::from_string("duplicate endpoints found")), 8),
(vec!["d1", "d2", "d3", "d1"], Some(Error::other("duplicate endpoints found")), 7),
(vec!["d1", "d2", "d3", "./d1"], Some(Error::other("duplicate endpoints found")), 8),
(
vec![
"http://localhost/d1",
@@ -673,17 +672,17 @@ mod test {
"http://localhost/d1",
"http://localhost/d4",
],
Some(Error::from_string("duplicate endpoints found")),
Some(Error::other("duplicate endpoints found")),
9,
),
(
vec!["ftp://server/d1", "http://server/d2", "http://server/d3", "http://server/d4"],
Some(Error::from_string("'ftp://server/d1': invalid URL endpoint format")),
Some(Error::other("'ftp://server/d1': invalid URL endpoint format")),
10,
),
(
vec!["d1", "http://localhost/d2", "d3", "d4"],
Some(Error::from_string("mixed style endpoints are not supported")),
Some(Error::other("mixed style endpoints are not supported")),
11,
),
(
@@ -693,7 +692,7 @@ mod test {
"http://example.net/d1",
"https://example.edut/d1",
],
Some(Error::from_string("mixed scheme is not supported")),
Some(Error::other("mixed scheme is not supported")),
12,
),
(
@@ -703,7 +702,7 @@ mod test {
"192.168.1.210:9000/tmp/dir2",
"192.168.110:9000/tmp/dir3",
],
Some(Error::from_string(
Some(Error::other(
"'192.168.1.210:9000/tmp/dir0': invalid URL endpoint format: missing scheme http or https",
)),
13,
@@ -811,7 +810,7 @@ mod test {
TestCase {
num: 1,
server_addr: "localhost",
expected_err: Some(Error::from_string("address localhost: missing port in address")),
expected_err: Some(Error::other("address localhost: missing port in address")),
..Default::default()
},
// Erasure Single Drive
@@ -819,7 +818,7 @@ mod test {
num: 2,
server_addr: "localhost:9000",
args: vec!["http://localhost/d1"],
expected_err: Some(Error::from_string("use path style endpoint for single node setup")),
expected_err: Some(Error::other("use path style endpoint for single node setup")),
..Default::default()
},
TestCase {
@@ -859,7 +858,7 @@ mod test {
"https://example.com/d1",
"https://example.com/d2",
],
expected_err: Some(Error::from_string("same path '/d1' can not be served by different port on same address")),
expected_err: Some(Error::other("same path '/d1' can not be served by different port on same address")),
..Default::default()
},
// Erasure Setup with PathEndpointType
@@ -953,7 +952,7 @@ mod test {
"http://127.0.0.1/d3",
"http://127.0.0.1/d4",
],
expected_err: Some(Error::from_string("all local endpoints should not have different hostnames/ips")),
expected_err: Some(Error::other("all local endpoints should not have different hostnames/ips")),
..Default::default()
},
TestCase {
@@ -965,9 +964,7 @@ mod test {
case7_endpoint1.as_str(),
"http://10.0.0.2:9001/export",
],
expected_err: Some(Error::from_string(
"same path '/export' can not be served by different port on same address",
)),
expected_err: Some(Error::other("same path '/export' can not be served by different port on same address")),
..Default::default()
},
TestCase {
@@ -979,7 +976,7 @@ mod test {
"http://10.0.0.1:9000/export",
"http://10.0.0.2:9000/export",
],
expected_err: Some(Error::from_string("path '/export' cannot be served by different address on same server")),
expected_err: Some(Error::other("path '/export' cannot be served by different address on same server")),
..Default::default()
},
// DistErasure type
+2 -6
View File
@@ -1,6 +1,6 @@
use crate::bitrot::{BitrotReader, BitrotWriter};
use crate::disk::error::{Error, Result};
use crate::disk::error_reduce::{reduce_write_quorum_errs, OBJECT_OP_IGNORED_ERRS};
use crate::disk::error_reduce::{OBJECT_OP_IGNORED_ERRS, reduce_write_quorum_errs};
use crate::io::Etag;
use bytes::{Bytes, BytesMut};
use futures::future::join_all;
@@ -72,11 +72,7 @@ impl Erasure {
if total_size > 0 {
let new_len = {
let remain = total_size - total;
if remain > self.block_size {
self.block_size
} else {
remain
}
if remain > self.block_size { self.block_size } else { remain }
};
if new_len == 0 && total > 0 {
+6
View File
@@ -164,6 +164,9 @@ pub enum StorageError {
#[error("first disk wiat")]
FirstDiskWait,
#[error("Bucket policy not found")]
BucketPolicyNotFound,
#[error("Io error: {0}")]
Io(std::io::Error),
}
@@ -376,6 +379,7 @@ impl Clone for StorageError {
StorageError::FirstDiskWait => StorageError::FirstDiskWait,
StorageError::TooManyOpenFiles => StorageError::TooManyOpenFiles,
StorageError::NoHealRequired => StorageError::NoHealRequired,
StorageError::BucketPolicyNotFound => StorageError::BucketPolicyNotFound,
}
}
}
@@ -438,6 +442,7 @@ impl StorageError {
StorageError::ConfigNotFound => 0x35,
StorageError::TooManyOpenFiles => 0x36,
StorageError::NoHealRequired => 0x37,
StorageError::BucketPolicyNotFound => 0x38,
}
}
@@ -502,6 +507,7 @@ impl StorageError {
0x35 => Some(StorageError::ConfigNotFound),
0x36 => Some(StorageError::TooManyOpenFiles),
0x37 => Some(StorageError::NoHealRequired),
0x38 => Some(StorageError::BucketPolicyNotFound),
_ => None,
}
}
+3399 -3399
View File
File diff suppressed because it is too large Load Diff
+1 -5
View File
@@ -27,11 +27,7 @@ impl InlineData {
}
pub fn after_version(&self) -> &[u8] {
if self.0.is_empty() {
&self.0
} else {
&self.0[1..]
}
if self.0.is_empty() { &self.0 } else { &self.0[1..] }
}
pub fn find(&self, key: &str) -> Result<Option<Vec<u8>>> {
+56 -70
View File
@@ -1,7 +1,7 @@
use crate::disk::error_reduce::{reduce_read_quorum_errs, reduce_write_quorum_errs, OBJECT_OP_IGNORED_ERRS};
use crate::disk::error_reduce::{OBJECT_OP_IGNORED_ERRS, reduce_read_quorum_errs, reduce_write_quorum_errs};
use crate::disk::{
self, conv_part_err_to_int, has_part_err, CHECK_PART_DISK_NOT_FOUND, CHECK_PART_FILE_CORRUPT, CHECK_PART_FILE_NOT_FOUND,
CHECK_PART_SUCCESS,
self, CHECK_PART_DISK_NOT_FOUND, CHECK_PART_FILE_CORRUPT, CHECK_PART_FILE_NOT_FOUND, CHECK_PART_SUCCESS,
conv_part_err_to_int, has_part_err,
};
use crate::erasure_coding;
use crate::error::{Error, Result};
@@ -9,24 +9,24 @@ use crate::global::GLOBAL_MRFState;
use crate::heal::data_usage_cache::DataUsageCache;
use crate::store_api::ObjectToDelete;
use crate::{
cache_value::metacache_set::{list_path_raw, ListPathRawOptions},
config::{storageclass, GLOBAL_StorageClass},
cache_value::metacache_set::{ListPathRawOptions, list_path_raw},
config::{GLOBAL_StorageClass, storageclass},
disk::{
endpoint::Endpoint, error::DiskError, format::FormatV3, new_disk, CheckPartsResp, DeleteOptions, DiskAPI, DiskInfo,
DiskInfoOptions, DiskOption, DiskStore, FileInfoVersions, ReadMultipleReq, ReadMultipleResp, ReadOptions,
UpdateMetadataOpts, RUSTFS_META_BUCKET, RUSTFS_META_MULTIPART_BUCKET, RUSTFS_META_TMP_BUCKET,
CheckPartsResp, DeleteOptions, DiskAPI, DiskInfo, DiskInfoOptions, DiskOption, DiskStore, FileInfoVersions,
RUSTFS_META_BUCKET, RUSTFS_META_MULTIPART_BUCKET, RUSTFS_META_TMP_BUCKET, ReadMultipleReq, ReadMultipleResp, ReadOptions,
UpdateMetadataOpts, endpoint::Endpoint, error::DiskError, format::FormatV3, new_disk,
},
error::{to_object_err, StorageError},
error::{StorageError, to_object_err},
global::{
get_global_deployment_id, is_dist_erasure, GLOBAL_BackgroundHealState, GLOBAL_LOCAL_DISK_MAP,
GLOBAL_LOCAL_DISK_SET_DRIVES,
GLOBAL_BackgroundHealState, GLOBAL_LOCAL_DISK_MAP, GLOBAL_LOCAL_DISK_SET_DRIVES, get_global_deployment_id,
is_dist_erasure,
},
heal::{
data_usage::{DATA_USAGE_CACHE_NAME, DATA_USAGE_ROOT},
data_usage_cache::{DataUsageCacheInfo, DataUsageEntry, DataUsageEntryInfo},
heal_commands::{
HealOpts, HealScanMode, HealingTracker, DRIVE_STATE_CORRUPT, DRIVE_STATE_MISSING, DRIVE_STATE_OFFLINE,
DRIVE_STATE_OK, HEAL_DEEP_SCAN, HEAL_ITEM_OBJECT, HEAL_NORMAL_SCAN,
DRIVE_STATE_CORRUPT, DRIVE_STATE_MISSING, DRIVE_STATE_OFFLINE, DRIVE_STATE_OK, HEAL_DEEP_SCAN, HEAL_ITEM_OBJECT,
HEAL_NORMAL_SCAN, HealOpts, HealScanMode, HealingTracker,
},
heal_ops::BG_HEALING_UUID,
},
@@ -39,13 +39,13 @@ use crate::{
store_init::load_format_erasure,
utils::{
crypto::{base64_decode, base64_encode, hex},
path::{encode_dir_object, has_suffix, SLASH_SEPARATOR},
path::{SLASH_SEPARATOR, encode_dir_object, has_suffix},
},
xhttp,
};
use crate::{disk::STORAGE_FORMAT_FILE, heal::mrf::PartialOperation};
use crate::{
heal::data_scanner::{globalHealConfig, HEAL_DELETE_DANGLING},
heal::data_scanner::{HEAL_DELETE_DANGLING, globalHealConfig},
store_api::ListObjectVersionsInfo,
};
use crate::{
@@ -57,18 +57,18 @@ use chrono::Utc;
use futures::future::join_all;
use glob::Pattern;
use http::HeaderMap;
use lock::{namespace_lock::NsLockMap, LockApi};
use lock::{LockApi, namespace_lock::NsLockMap};
use madmin::heal_commands::{HealDriveInfo, HealResultItem};
use md5::{Digest as Md5Digest, Md5};
use rand::{
thread_rng,
{seq::SliceRandom, Rng},
{Rng, seq::SliceRandom},
};
use rustfs_filemeta::{
file_info_from_raw, merge_file_meta_versions, FileInfo, FileMeta, FileMetaShallowVersion, MetaCacheEntries, MetaCacheEntry,
MetadataResolutionParams, ObjectPartInfo, RawFileInfo,
FileInfo, FileMeta, FileMetaShallowVersion, MetaCacheEntries, MetaCacheEntry, MetadataResolutionParams, ObjectPartInfo,
RawFileInfo, file_info_from_raw, merge_file_meta_versions,
};
use rustfs_rio::{bitrot_verify, BitrotReader, BitrotWriter, EtagResolvable, HashReader, Writer};
use rustfs_rio::{BitrotReader, BitrotWriter, EtagResolvable, HashReader, Writer, bitrot_verify};
use rustfs_utils::HashAlgorithm;
use sha2::{Digest, Sha256};
use std::hash::Hash;
@@ -84,8 +84,8 @@ use std::{
};
use time::OffsetDateTime;
use tokio::{
io::{empty, AsyncWrite},
sync::{broadcast, RwLock},
io::{AsyncWrite, empty},
sync::{RwLock, broadcast},
};
use tokio::{
select,
@@ -406,11 +406,7 @@ impl SetDisks {
}
}
if max >= write_quorum {
data_dir
} else {
None
}
if max >= write_quorum { data_dir } else { None }
}
#[allow(dead_code)]
@@ -741,11 +737,7 @@ impl SetDisks {
fn common_time(times: &[Option<OffsetDateTime>], quorum: usize) -> Option<OffsetDateTime> {
let (time, count) = Self::common_time_and_occurrence(times);
if count >= quorum {
time
} else {
None
}
if count >= quorum { time } else { None }
}
fn common_time_and_occurrence(times: &[Option<OffsetDateTime>]) -> (Option<OffsetDateTime>, usize) {
@@ -786,11 +778,7 @@ impl SetDisks {
fn common_etag(etags: &[Option<String>], quorum: usize) -> Option<String> {
let (etag, count) = Self::common_etags(etags);
if count >= quorum {
etag
} else {
None
}
if count >= quorum { etag } else { None }
}
fn common_etags(etags: &[Option<String>]) -> (Option<String>, usize) {
@@ -1837,13 +1825,7 @@ impl SetDisks {
let total_size = fi.size;
let length = {
if length == 0 {
total_size - offset
} else {
length
}
};
let length = { if length == 0 { total_size - offset } else { length } };
if offset > total_size || offset + length > total_size {
return Err(Error::other("offset out of range"));
@@ -1896,12 +1878,16 @@ impl SetDisks {
readers.push(Some(reader));
errors.push(None);
} else if let Some(disk) = disk_op {
// Calculate ceiling division of till_offset by shard_size
let till_offset =
till_offset.div_ceil(erasure.shard_size()) * HashAlgorithm::HighwayHash256.size() + till_offset;
let rd = disk
.read_file_stream(
bucket,
&format!("{}/{}/part.{}", object, files[idx].data_dir.unwrap_or(Uuid::nil()), part_number),
part_offset,
till_offset,
part_length,
)
.await?;
let reader = BitrotReader::new(rd, erasure.shard_size(), HashAlgorithm::HighwayHash256);
@@ -2403,8 +2389,10 @@ impl SetDisks {
}
if !lastest_meta.deleted && lastest_meta.erasure.distribution.len() != available_disks.len() {
let err_str = format!("unexpected file distribution ({:?}) from available disks ({:?}), looks like backend disks have been manually modified refusing to heal {}/{}({})",
lastest_meta.erasure.distribution, available_disks, bucket, object, version_id);
let err_str = format!(
"unexpected file distribution ({:?}) from available disks ({:?}), looks like backend disks have been manually modified refusing to heal {}/{}({})",
lastest_meta.erasure.distribution, available_disks, bucket, object, version_id
);
warn!(err_str);
let err = DiskError::other(err_str);
return Ok((
@@ -2416,8 +2404,10 @@ impl SetDisks {
let latest_disks = Self::shuffle_disks(&available_disks, &lastest_meta.erasure.distribution);
if !lastest_meta.deleted && lastest_meta.erasure.distribution.len() != outdate_disks.len() {
let err_str = format!("unexpected file distribution ({:?}) from outdated disks ({:?}), looks like backend disks have been manually modified refusing to heal {}/{}({})",
lastest_meta.erasure.distribution, outdate_disks, bucket, object, version_id);
let err_str = format!(
"unexpected file distribution ({:?}) from outdated disks ({:?}), looks like backend disks have been manually modified refusing to heal {}/{}({})",
lastest_meta.erasure.distribution, outdate_disks, bucket, object, version_id
);
warn!(err_str);
let err = DiskError::other(err_str);
return Ok((
@@ -2428,8 +2418,14 @@ impl SetDisks {
}
if !lastest_meta.deleted && lastest_meta.erasure.distribution.len() != parts_metadata.len() {
let err_str = format!("unexpected file distribution ({:?}) from metadata entries ({:?}), looks like backend disks have been manually modified refusing to heal {}/{}({})",
lastest_meta.erasure.distribution, parts_metadata.len(), bucket, object, version_id);
let err_str = format!(
"unexpected file distribution ({:?}) from metadata entries ({:?}), looks like backend disks have been manually modified refusing to heal {}/{}({})",
lastest_meta.erasure.distribution,
parts_metadata.len(),
bucket,
object,
version_id
);
warn!(err_str);
let err = DiskError::other(err_str);
return Ok((
@@ -3907,6 +3903,7 @@ impl ObjectIO for SetDisks {
};
writers.push(Some(writer));
errors.push(None);
} else {
errors.push(Some(DiskError::DiskNotFound));
writers.push(None);
@@ -3915,6 +3912,7 @@ impl ObjectIO for SetDisks {
let nil_count = errors.iter().filter(|&e| e.is_none()).count();
if nil_count < write_quorum {
error!("not enough disks to write: {:?}", errors);
if let Some(write_err) = reduce_write_quorum_errs(&errors, OBJECT_OP_IGNORED_ERRS, write_quorum) {
return Err(to_object_err(write_err.into(), vec![bucket, object]));
}
@@ -3926,7 +3924,7 @@ impl ObjectIO for SetDisks {
let (reader, w_size) = Arc::new(erasure).encode(stream, &mut writers, write_quorum).await?; // TODO: 出错,删除临时目录
mem::replace(&mut data.stream, reader);
let _ = mem::replace(&mut data.stream, reader);
// if let Err(err) = close_bitrot_writers(&mut writers).await {
// error!("close_bitrot_writers err {:?}", err);
// }
@@ -4549,25 +4547,11 @@ impl StorageAPI for SetDisks {
let erasure = erasure_coding::Erasure::new(fi.erasure.data_blocks, fi.erasure.parity_blocks, fi.erasure.block_size);
let is_inline_buffer = {
if let Some(sc) = GLOBAL_StorageClass.get() {
sc.should_inline(erasure.shard_file_size(data.content_length), opts.versioned)
} else {
false
}
};
let mut writers = Vec::with_capacity(shuffle_disks.len());
let mut errors = Vec::with_capacity(shuffle_disks.len());
for disk_op in shuffle_disks.iter() {
if let Some(disk) = disk_op {
let writer = if is_inline_buffer {
BitrotWriter::new(
Writer::from_cursor(Cursor::new(Vec::new())),
erasure.shard_size(),
HashAlgorithm::HighwayHash256,
)
} else {
let writer = {
let f = match disk
.create_file("", RUSTFS_META_TMP_BUCKET, &tmp_part_path, erasure.shard_file_size(data.content_length))
.await
@@ -4584,6 +4568,7 @@ impl StorageAPI for SetDisks {
};
writers.push(Some(writer));
errors.push(None);
} else {
errors.push(Some(DiskError::DiskNotFound));
writers.push(None);
@@ -4601,8 +4586,9 @@ impl StorageAPI for SetDisks {
let stream = mem::replace(&mut data.stream, HashReader::new(Box::new(Cursor::new(Vec::new())), 0, 0, None, false)?);
let (mut reader, w_size) = Arc::new(erasure).encode(stream, &mut writers, write_quorum).await?; // TODO: 出错,删除临时目录
mem::replace(&mut data.stream, reader);
let (reader, w_size) = Arc::new(erasure).encode(stream, &mut writers, write_quorum).await?; // TODO: 出错,删除临时目录
let _ = mem::replace(&mut data.stream, reader);
let mut etag = data.stream.try_resolve_etag().unwrap_or_default();
@@ -5755,9 +5741,9 @@ fn get_complete_multipart_md5(parts: &[CompletePart]) -> String {
#[cfg(test)]
mod tests {
use super::*;
use crate::disk::error::DiskError;
use crate::disk::CHECK_PART_UNKNOWN;
use crate::disk::CHECK_PART_VOLUME_NOT_FOUND;
use crate::disk::error::DiskError;
use crate::store_api::CompletePart;
use rustfs_filemeta::ErasureInfo;
use std::collections::HashMap;
+2 -2
View File
@@ -1,9 +1,9 @@
use common::error::{Error, Result};
use std::io::{Error, Result};
pub fn parse_bool(str: &str) -> Result<bool> {
match str {
"1" | "t" | "T" | "true" | "TRUE" | "True" | "on" | "ON" | "On" | "enabled" => Ok(true),
"0" | "f" | "F" | "false" | "FALSE" | "False" | "off" | "OFF" | "Off" | "disabled" => Ok(false),
_ => Err(Error::from_string(format!("ParseBool: parsing {}", str))),
_ => Err(Error::other(format!("ParseBool: parsing {}", str))),
}
}
+15 -9
View File
@@ -1,6 +1,6 @@
use common::error::{Error, Result};
use lazy_static::*;
use regex::Regex;
use std::io::{Error, Result};
lazy_static! {
static ref ELLIPSES_RE: Regex = Regex::new(r"(.*)(\{[0-9a-z]*\.\.\.[0-9a-z]*\})(.*)").unwrap();
@@ -107,7 +107,10 @@ pub fn find_ellipses_patterns(arg: &str) -> Result<ArgPattern> {
let mut parts = match ELLIPSES_RE.captures(arg) {
Some(caps) => caps,
None => {
return Err(Error::from_string(format!("Invalid ellipsis format in ({}), Ellipsis range must be provided in format {{N...M}} where N and M are positive integers, M must be greater than N, with an allowed minimum range of 4", arg)));
return Err(Error::other(format!(
"Invalid ellipsis format in ({}), Ellipsis range must be provided in format {{N...M}} where N and M are positive integers, M must be greater than N, with an allowed minimum range of 4",
arg
)));
}
};
@@ -144,7 +147,10 @@ pub fn find_ellipses_patterns(arg: &str) -> Result<ArgPattern> {
|| p.suffix.contains(OPEN_BRACES)
|| p.suffix.contains(CLOSE_BRACES)
{
return Err(Error::from_string(format!("Invalid ellipsis format in ({}), Ellipsis range must be provided in format {{N...M}} where N and M are positive integers, M must be greater than N, with an allowed minimum range of 4", arg)));
return Err(Error::other(format!(
"Invalid ellipsis format in ({}), Ellipsis range must be provided in format {{N...M}} where N and M are positive integers, M must be greater than N, with an allowed minimum range of 4",
arg
)));
}
}
@@ -165,10 +171,10 @@ pub fn has_ellipses<T: AsRef<str>>(s: &[T]) -> bool {
/// {33...64}
pub fn parse_ellipses_range(pattern: &str) -> Result<Vec<String>> {
if !pattern.contains(OPEN_BRACES) {
return Err(Error::from_string("Invalid argument"));
return Err(Error::other("Invalid argument"));
}
if !pattern.contains(OPEN_BRACES) {
return Err(Error::from_string("Invalid argument"));
return Err(Error::other("Invalid argument"));
}
let ellipses_range: Vec<&str> = pattern
@@ -178,15 +184,15 @@ pub fn parse_ellipses_range(pattern: &str) -> Result<Vec<String>> {
.collect();
if ellipses_range.len() != 2 {
return Err(Error::from_string("Invalid argument"));
return Err(Error::other("Invalid argument"));
}
// TODO: Add support for hexadecimals.
let start = ellipses_range[0].parse::<usize>()?;
let end = ellipses_range[1].parse::<usize>()?;
let start = ellipses_range[0].parse::<usize>().map_err(|e| Error::other(e))?;
let end = ellipses_range[1].parse::<usize>().map_err(|e| Error::other(e))?;
if start > end {
return Err(Error::from_string("Invalid argument:range start cannot be bigger than end"));
return Err(Error::other("Invalid argument:range start cannot be bigger than end"));
}
let mut ret: Vec<String> = Vec::with_capacity(end - start + 1);
+11 -14
View File
@@ -1,5 +1,5 @@
use common::error::{Error, Result};
use lazy_static::lazy_static;
use std::io::{Error, Result};
use std::{
collections::HashSet,
fmt::Display,
@@ -23,7 +23,7 @@ pub fn is_socket_addr(addr: &str) -> bool {
pub fn check_local_server_addr(server_addr: &str) -> Result<SocketAddr> {
let addr: Vec<SocketAddr> = match server_addr.to_socket_addrs() {
Ok(addr) => addr.collect(),
Err(err) => return Err(Error::new(Box::new(err))),
Err(err) => return Err(err),
};
// 0.0.0.0 is a wildcard address and refers to local network
@@ -44,7 +44,7 @@ pub fn check_local_server_addr(server_addr: &str) -> Result<SocketAddr> {
}
}
Err(Error::from_string("host in server address should be this server"))
Err(Error::other("host in server address should be this server"))
}
/// checks if the given parameter correspond to one of
@@ -55,7 +55,7 @@ pub fn is_local_host(host: Host<&str>, port: u16, local_port: u16) -> Result<boo
Host::Domain(domain) => {
let ips = match (domain, 0).to_socket_addrs().map(|v| v.map(|v| v.ip()).collect::<Vec<_>>()) {
Ok(ips) => ips,
Err(err) => return Err(Error::new(Box::new(err))),
Err(err) => return Err(err),
};
ips.iter().any(|ip| local_set.contains(ip))
@@ -79,7 +79,7 @@ pub fn get_host_ip(host: Host<&str>) -> Result<HashSet<IpAddr>> {
.map(|v| v.map(|v| v.ip()).collect::<HashSet<_>>())
{
Ok(ips) => Ok(ips),
Err(err) => Err(Error::new(Box::new(err))),
Err(err) => Err(err),
},
Host::Ipv4(ip) => {
let mut set = HashSet::with_capacity(1);
@@ -102,7 +102,7 @@ pub fn get_available_port() -> u16 {
pub(crate) fn must_get_local_ips() -> Result<Vec<IpAddr>> {
match netif::up() {
Ok(up) => Ok(up.map(|x| x.address().to_owned()).collect()),
Err(err) => Err(Error::from_string(format!("Unable to get IP addresses of this host: {}", err))),
Err(err) => Err(Error::other(format!("Unable to get IP addresses of this host: {}", err))),
}
}
@@ -149,7 +149,7 @@ pub fn parse_and_resolve_address(addr_str: &str) -> Result<SocketAddr> {
let port_str = port;
let port: u16 = port_str
.parse()
.map_err(|e| Error::from_string(format!("Invalid port format: {}, err:{:?}", addr_str, e)))?;
.map_err(|e| Error::other(format!("Invalid port format: {}, err:{:?}", addr_str, e)))?;
let final_port = if port == 0 {
get_available_port() // assume get_available_port is available here
} else {
@@ -199,13 +199,10 @@ mod test {
("localhost:54321", Ok(())),
("0.0.0.0:9000", Ok(())),
// (":0", Ok(())),
("localhost", Err(Error::from_string("invalid socket address"))),
("", Err(Error::from_string("invalid socket address"))),
(
"example.org:54321",
Err(Error::from_string("host in server address should be this server")),
),
(":-10", Err(Error::from_string("invalid port value"))),
("localhost", Err(Error::other("invalid socket address"))),
("", Err(Error::other("invalid socket address"))),
("example.org:54321", Err(Error::other("host in server address should be this server"))),
(":-10", Err(Error::other("invalid port value"))),
];
for test_case in test_cases {
+6 -6
View File
@@ -1,11 +1,11 @@
use nix::sys::stat::{self, stat};
use nix::sys::statfs::{self, statfs, FsType};
use nix::sys::statfs::{self, FsType, statfs};
use std::fs::File;
use std::io::{self, BufRead, Error, ErrorKind};
use std::path::Path;
use crate::disk::Info;
use common::error::{Error as e_Error, Result};
use std::io::{Error, Result};
use super::IOStats;
@@ -29,7 +29,7 @@ pub fn get_info(p: impl AsRef<Path>) -> std::io::Result<Info> {
bfree,
p.as_ref().display()
),
))
));
}
};
@@ -44,7 +44,7 @@ pub fn get_info(p: impl AsRef<Path>) -> std::io::Result<Info> {
blocks,
p.as_ref().display()
),
))
));
}
};
@@ -60,7 +60,7 @@ pub fn get_info(p: impl AsRef<Path>) -> std::io::Result<Info> {
total,
p.as_ref().display()
),
))
));
}
};
@@ -122,7 +122,7 @@ pub fn get_drive_stats(major: u32, minor: u32) -> Result<IOStats> {
fn read_drive_stats(stats_file: &str) -> Result<IOStats> {
let stats = read_stat(stats_file)?;
if stats.len() < 11 {
return Err(e_Error::from_string(format!("found invalid format while reading {}", stats_file)));
return Err(Error::new(ErrorKind::Other, format!("found invalid format while reading {}", stats_file)));
}
let mut io_stats = IOStats {
read_ios: stats[0],
+4 -5
View File
@@ -1,8 +1,7 @@
use super::IOStats;
use crate::disk::Info;
use common::error::Result;
use nix::sys::{stat::stat, statfs::statfs};
use std::io::Error;
use std::io::{Error, Result};
use std::path::Path;
/// returns total and free bytes available in a directory, e.g. `/`.
@@ -22,7 +21,7 @@ pub fn get_info(p: impl AsRef<Path>) -> std::io::Result<Info> {
bavail,
bfree,
p.as_ref().display()
)))
)));
}
};
@@ -34,7 +33,7 @@ pub fn get_info(p: impl AsRef<Path>) -> std::io::Result<Info> {
reserved,
blocks,
p.as_ref().display()
)))
)));
}
};
@@ -47,7 +46,7 @@ pub fn get_info(p: impl AsRef<Path>) -> std::io::Result<Info> {
free,
total,
p.as_ref().display()
)))
)));
}
};
+1 -2
View File
@@ -2,8 +2,7 @@
use super::IOStats;
use crate::disk::Info;
use common::error::Result;
use std::io::{Error, ErrorKind};
use std::io::{Error, ErrorKind, Result};
use std::mem;
use std::os::windows::ffi::OsStrExt;
use std::path::Path;