mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-29 08:27:06 +00:00
fix: filemeta version handling and delete operations (#879)
* fix filemeta version * fix clippy * fix delete version * fix clippy/test
This commit is contained in:
@@ -363,7 +363,7 @@ impl ErasureSetHealer {
|
|||||||
let _permit = semaphore
|
let _permit = semaphore
|
||||||
.acquire()
|
.acquire()
|
||||||
.await
|
.await
|
||||||
.map_err(|e| Error::other(format!("Failed to acquire semaphore for bucket heal: {}", e)))?;
|
.map_err(|e| Error::other(format!("Failed to acquire semaphore for bucket heal: {e}")))?;
|
||||||
|
|
||||||
if cancel_token.is_cancelled() {
|
if cancel_token.is_cancelled() {
|
||||||
return Err(Error::TaskCancelled);
|
return Err(Error::TaskCancelled);
|
||||||
@@ -461,7 +461,7 @@ impl ErasureSetHealer {
|
|||||||
let _permit = semaphore
|
let _permit = semaphore
|
||||||
.acquire()
|
.acquire()
|
||||||
.await
|
.await
|
||||||
.map_err(|e| Error::other(format!("Failed to acquire semaphore for object heal: {}", e)))?;
|
.map_err(|e| Error::other(format!("Failed to acquire semaphore for object heal: {e}")))?;
|
||||||
|
|
||||||
match storage.heal_object(&bucket, &object, None, &heal_opts).await {
|
match storage.heal_object(&bucket, &object, None, &heal_opts).await {
|
||||||
Ok((_result, None)) => {
|
Ok((_result, None)) => {
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ const RESUME_CHECKPOINT_FILE: &str = "ahm_checkpoint.json";
|
|||||||
/// Helper function to convert Path to &str, returning an error if conversion fails
|
/// Helper function to convert Path to &str, returning an error if conversion fails
|
||||||
fn path_to_str(path: &Path) -> Result<&str> {
|
fn path_to_str(path: &Path) -> Result<&str> {
|
||||||
path.to_str()
|
path.to_str()
|
||||||
.ok_or_else(|| Error::other(format!("Invalid UTF-8 path: {:?}", path)))
|
.ok_or_else(|| Error::other(format!("Invalid UTF-8 path: {path:?}")))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// resume state
|
/// resume state
|
||||||
|
|||||||
@@ -180,8 +180,7 @@ impl HealStorageAPI for ECStoreHealStorage {
|
|||||||
MAX_READ_BYTES, bucket, object
|
MAX_READ_BYTES, bucket, object
|
||||||
);
|
);
|
||||||
return Err(Error::other(format!(
|
return Err(Error::other(format!(
|
||||||
"Object too large: {} bytes (max: {} bytes) for {}/{}",
|
"Object too large: {n_read} bytes (max: {MAX_READ_BYTES} bytes) for {bucket}/{object}"
|
||||||
n_read, MAX_READ_BYTES, bucket, object
|
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -144,7 +144,7 @@ async fn setup_test_env() -> (Vec<PathBuf>, Arc<ECStore>) {
|
|||||||
let mut wtxn = lmdb_env.write_txn().unwrap();
|
let mut wtxn = lmdb_env.write_txn().unwrap();
|
||||||
let db = match lmdb_env
|
let db = match lmdb_env
|
||||||
.database_options()
|
.database_options()
|
||||||
.name(&format!("bucket_{}", bucket_name))
|
.name(&format!("bucket_{bucket_name}"))
|
||||||
.types::<I64<BigEndian>, LifecycleContentCodec>()
|
.types::<I64<BigEndian>, LifecycleContentCodec>()
|
||||||
.flags(DatabaseFlags::DUP_SORT)
|
.flags(DatabaseFlags::DUP_SORT)
|
||||||
//.dup_sort_comparator::<>()
|
//.dup_sort_comparator::<>()
|
||||||
@@ -152,7 +152,7 @@ async fn setup_test_env() -> (Vec<PathBuf>, Arc<ECStore>) {
|
|||||||
{
|
{
|
||||||
Ok(db) => db,
|
Ok(db) => db,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
panic!("lmdb error: {}", err);
|
panic!("lmdb error: {err}");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let _ = wtxn.commit();
|
let _ = wtxn.commit();
|
||||||
@@ -199,7 +199,7 @@ async fn upload_test_object(ecstore: &Arc<ECStore>, bucket: &str, object: &str,
|
|||||||
.await
|
.await
|
||||||
.expect("Failed to upload test object");
|
.expect("Failed to upload test object");
|
||||||
|
|
||||||
println!("object_info1: {:?}", object_info);
|
println!("object_info1: {object_info:?}");
|
||||||
|
|
||||||
info!("Uploaded test object: {}/{} ({} bytes)", bucket, object, object_info.size);
|
info!("Uploaded test object: {}/{} ({} bytes)", bucket, object, object_info.size);
|
||||||
}
|
}
|
||||||
@@ -456,7 +456,7 @@ mod serial_tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let object_info = convert_record_to_object_info(record);
|
let object_info = convert_record_to_object_info(record);
|
||||||
println!("object_info2: {:?}", object_info);
|
println!("object_info2: {object_info:?}");
|
||||||
let mod_time = object_info.mod_time.unwrap_or(OffsetDateTime::now_utc());
|
let mod_time = object_info.mod_time.unwrap_or(OffsetDateTime::now_utc());
|
||||||
let expiry_time = rustfs_ecstore::bucket::lifecycle::lifecycle::expected_expiry_time(mod_time, 1);
|
let expiry_time = rustfs_ecstore::bucket::lifecycle::lifecycle::expected_expiry_time(mod_time, 1);
|
||||||
|
|
||||||
@@ -494,9 +494,9 @@ mod serial_tests {
|
|||||||
type_,
|
type_,
|
||||||
object_name,
|
object_name,
|
||||||
} = &elm.1;
|
} = &elm.1;
|
||||||
println!("cache row:{} {} {} {:?} {}", ver_no, ver_id, mod_time, type_, object_name);
|
println!("cache row:{ver_no} {ver_id} {mod_time} {type_:?} {object_name}");
|
||||||
}
|
}
|
||||||
println!("row:{:?}", row);
|
println!("row:{row:?}");
|
||||||
}
|
}
|
||||||
//drop(iter);
|
//drop(iter);
|
||||||
wtxn.commit().unwrap();
|
wtxn.commit().unwrap();
|
||||||
|
|||||||
@@ -277,11 +277,11 @@ async fn create_test_tier(server: u32) {
|
|||||||
};
|
};
|
||||||
let mut tier_config_mgr = GLOBAL_TierConfigMgr.write().await;
|
let mut tier_config_mgr = GLOBAL_TierConfigMgr.write().await;
|
||||||
if let Err(err) = tier_config_mgr.add(args, false).await {
|
if let Err(err) = tier_config_mgr.add(args, false).await {
|
||||||
println!("tier_config_mgr add failed, e: {:?}", err);
|
println!("tier_config_mgr add failed, e: {err:?}");
|
||||||
panic!("tier add failed. {err}");
|
panic!("tier add failed. {err}");
|
||||||
}
|
}
|
||||||
if let Err(e) = tier_config_mgr.save().await {
|
if let Err(e) = tier_config_mgr.save().await {
|
||||||
println!("tier_config_mgr save failed, e: {:?}", e);
|
println!("tier_config_mgr save failed, e: {e:?}");
|
||||||
panic!("tier save failed");
|
panic!("tier save failed");
|
||||||
}
|
}
|
||||||
println!("Created test tier: COLDTIER44");
|
println!("Created test tier: COLDTIER44");
|
||||||
@@ -299,7 +299,7 @@ async fn object_exists(ecstore: &Arc<ECStore>, bucket: &str, object: &str) -> bo
|
|||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
async fn object_is_delete_marker(ecstore: &Arc<ECStore>, bucket: &str, object: &str) -> bool {
|
async fn object_is_delete_marker(ecstore: &Arc<ECStore>, bucket: &str, object: &str) -> bool {
|
||||||
if let Ok(oi) = (**ecstore).get_object_info(bucket, object, &ObjectOptions::default()).await {
|
if let Ok(oi) = (**ecstore).get_object_info(bucket, object, &ObjectOptions::default()).await {
|
||||||
println!("oi: {:?}", oi);
|
println!("oi: {oi:?}");
|
||||||
oi.delete_marker
|
oi.delete_marker
|
||||||
} else {
|
} else {
|
||||||
println!("object_is_delete_marker is error");
|
println!("object_is_delete_marker is error");
|
||||||
@@ -311,7 +311,7 @@ async fn object_is_delete_marker(ecstore: &Arc<ECStore>, bucket: &str, object: &
|
|||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
async fn object_is_transitioned(ecstore: &Arc<ECStore>, bucket: &str, object: &str) -> bool {
|
async fn object_is_transitioned(ecstore: &Arc<ECStore>, bucket: &str, object: &str) -> bool {
|
||||||
if let Ok(oi) = (**ecstore).get_object_info(bucket, object, &ObjectOptions::default()).await {
|
if let Ok(oi) = (**ecstore).get_object_info(bucket, object, &ObjectOptions::default()).await {
|
||||||
println!("oi: {:?}", oi);
|
println!("oi: {oi:?}");
|
||||||
!oi.transitioned_object.status.is_empty()
|
!oi.transitioned_object.status.is_empty()
|
||||||
} else {
|
} else {
|
||||||
println!("object_is_transitioned is error");
|
println!("object_is_transitioned is error");
|
||||||
|
|||||||
@@ -1106,18 +1106,15 @@ impl TargetClient {
|
|||||||
SdkError::ServiceError(oe) => match oe.into_err() {
|
SdkError::ServiceError(oe) => match oe.into_err() {
|
||||||
HeadBucketError::NotFound(_) => Ok(false),
|
HeadBucketError::NotFound(_) => Ok(false),
|
||||||
other => Err(S3ClientError::new(format!(
|
other => Err(S3ClientError::new(format!(
|
||||||
"failed to check bucket exists for bucket:{} please check the bucket name and credentials, error:{:?}",
|
"failed to check bucket exists for bucket:{bucket} please check the bucket name and credentials, error:{other:?}"
|
||||||
bucket, other
|
|
||||||
))),
|
))),
|
||||||
},
|
},
|
||||||
SdkError::DispatchFailure(e) => Err(S3ClientError::new(format!(
|
SdkError::DispatchFailure(e) => Err(S3ClientError::new(format!(
|
||||||
"failed to dispatch bucket exists for bucket:{} error:{:?}",
|
"failed to dispatch bucket exists for bucket:{bucket} error:{e:?}"
|
||||||
bucket, e
|
|
||||||
))),
|
))),
|
||||||
|
|
||||||
_ => Err(S3ClientError::new(format!(
|
_ => Err(S3ClientError::new(format!(
|
||||||
"failed to check bucket exists for bucket:{} error:{:?}",
|
"failed to check bucket exists for bucket:{bucket} error:{e:?}"
|
||||||
bucket, e
|
|
||||||
))),
|
))),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -806,7 +806,7 @@ impl LocalDisk {
|
|||||||
Ok((bytes, modtime))
|
Ok((bytes, modtime))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn delete_versions_internal(&self, volume: &str, path: &str, fis: &Vec<FileInfo>) -> Result<()> {
|
async fn delete_versions_internal(&self, volume: &str, path: &str, fis: &[FileInfo]) -> Result<()> {
|
||||||
let volume_dir = self.get_bucket_path(volume)?;
|
let volume_dir = self.get_bucket_path(volume)?;
|
||||||
let xlpath = self.get_object_path(volume, format!("{path}/{STORAGE_FORMAT_FILE}").as_str())?;
|
let xlpath = self.get_object_path(volume, format!("{path}/{STORAGE_FORMAT_FILE}").as_str())?;
|
||||||
|
|
||||||
@@ -820,7 +820,7 @@ impl LocalDisk {
|
|||||||
|
|
||||||
fm.unmarshal_msg(&data)?;
|
fm.unmarshal_msg(&data)?;
|
||||||
|
|
||||||
for fi in fis {
|
for fi in fis.iter() {
|
||||||
let data_dir = match fm.delete_version(fi) {
|
let data_dir = match fm.delete_version(fi) {
|
||||||
Ok(res) => res,
|
Ok(res) => res,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
@@ -2300,7 +2300,6 @@ impl DiskAPI for LocalDisk {
|
|||||||
let buf = match self.read_all_data(volume, &volume_dir, &xl_path).await {
|
let buf = match self.read_all_data(volume, &volume_dir, &xl_path).await {
|
||||||
Ok(res) => res,
|
Ok(res) => res,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
//
|
|
||||||
if err != DiskError::FileNotFound {
|
if err != DiskError::FileNotFound {
|
||||||
return Err(err);
|
return Err(err);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1085,7 +1085,7 @@ mod tests {
|
|||||||
|
|
||||||
drop(listener);
|
drop(listener);
|
||||||
|
|
||||||
let url = url::Url::parse(&format!("http://{}:{}/data/rustfs0", ip, port)).unwrap();
|
let url = url::Url::parse(&format!("http://{ip}:{port}/data/rustfs0")).unwrap();
|
||||||
let endpoint = Endpoint {
|
let endpoint = Endpoint {
|
||||||
url,
|
url,
|
||||||
is_local: false,
|
is_local: false,
|
||||||
|
|||||||
@@ -4247,7 +4247,6 @@ impl StorageAPI for SetDisks {
|
|||||||
|
|
||||||
for (_, mut fi_vers) in vers_map {
|
for (_, mut fi_vers) in vers_map {
|
||||||
fi_vers.versions.sort_by(|a, b| a.deleted.cmp(&b.deleted));
|
fi_vers.versions.sort_by(|a, b| a.deleted.cmp(&b.deleted));
|
||||||
fi_vers.versions.reverse();
|
|
||||||
|
|
||||||
if let Some(index) = fi_vers.versions.iter().position(|fi| fi.deleted) {
|
if let Some(index) = fi_vers.versions.iter().position(|fi| fi.deleted) {
|
||||||
fi_vers.versions.truncate(index + 1);
|
fi_vers.versions.truncate(index + 1);
|
||||||
@@ -4652,7 +4651,7 @@ impl StorageAPI for SetDisks {
|
|||||||
let tgt_client = match tier_config_mgr.get_driver(&opts.transition.tier).await {
|
let tgt_client = match tier_config_mgr.get_driver(&opts.transition.tier).await {
|
||||||
Ok(client) => client,
|
Ok(client) => client,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
return Err(Error::other(format!("remote tier error: {}", err)));
|
return Err(Error::other(format!("remote tier error: {err}")));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -427,11 +427,19 @@ impl FileMeta {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.versions.reverse();
|
self.versions.sort_by(|a, b| {
|
||||||
|
if a.header.mod_time != b.header.mod_time {
|
||||||
// for _v in self.versions.iter() {
|
b.header.mod_time.cmp(&a.header.mod_time)
|
||||||
// // warn!("sort {} {:?}", i, v);
|
} else if a.header.version_type != b.header.version_type {
|
||||||
// }
|
b.header.version_type.cmp(&a.header.version_type)
|
||||||
|
} else if a.header.version_id != b.header.version_id {
|
||||||
|
b.header.version_id.cmp(&a.header.version_id)
|
||||||
|
} else if a.header.flags != b.header.flags {
|
||||||
|
b.header.flags.cmp(&a.header.flags)
|
||||||
|
} else {
|
||||||
|
b.cmp(a)
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find version
|
// Find version
|
||||||
@@ -489,25 +497,27 @@ impl FileMeta {
|
|||||||
|
|
||||||
self.versions.sort_by(|a, b| {
|
self.versions.sort_by(|a, b| {
|
||||||
if a.header.mod_time != b.header.mod_time {
|
if a.header.mod_time != b.header.mod_time {
|
||||||
a.header.mod_time.cmp(&b.header.mod_time)
|
b.header.mod_time.cmp(&a.header.mod_time)
|
||||||
} else if a.header.version_type != b.header.version_type {
|
} else if a.header.version_type != b.header.version_type {
|
||||||
a.header.version_type.cmp(&b.header.version_type)
|
b.header.version_type.cmp(&a.header.version_type)
|
||||||
} else if a.header.version_id != b.header.version_id {
|
} else if a.header.version_id != b.header.version_id {
|
||||||
a.header.version_id.cmp(&b.header.version_id)
|
b.header.version_id.cmp(&a.header.version_id)
|
||||||
} else if a.header.flags != b.header.flags {
|
} else if a.header.flags != b.header.flags {
|
||||||
a.header.flags.cmp(&b.header.flags)
|
b.header.flags.cmp(&a.header.flags)
|
||||||
} else {
|
} else {
|
||||||
a.cmp(b)
|
b.cmp(a)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_version(&mut self, fi: FileInfo) -> Result<()> {
|
pub fn add_version(&mut self, mut fi: FileInfo) -> Result<()> {
|
||||||
let vid = fi.version_id;
|
if fi.version_id.is_none() {
|
||||||
|
fi.version_id = Some(Uuid::nil());
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(ref data) = fi.data {
|
if let Some(ref data) = fi.data {
|
||||||
let key = vid.unwrap_or_default().to_string();
|
let key = fi.version_id.unwrap_or_default().to_string();
|
||||||
self.data.replace(&key, data.to_vec())?;
|
self.data.replace(&key, data.to_vec())?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -551,7 +561,6 @@ impl FileMeta {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Err(Error::other("add_version failed"))
|
Err(Error::other("add_version failed"))
|
||||||
|
|
||||||
// if !ver.valid() {
|
// if !ver.valid() {
|
||||||
@@ -583,12 +592,19 @@ impl FileMeta {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// delete_version deletes version, returns data_dir
|
// delete_version deletes version, returns data_dir
|
||||||
|
#[tracing::instrument(skip(self))]
|
||||||
pub fn delete_version(&mut self, fi: &FileInfo) -> Result<Option<Uuid>> {
|
pub fn delete_version(&mut self, fi: &FileInfo) -> Result<Option<Uuid>> {
|
||||||
|
let vid = if fi.version_id.is_none() {
|
||||||
|
Some(Uuid::nil())
|
||||||
|
} else {
|
||||||
|
Some(fi.version_id.unwrap())
|
||||||
|
};
|
||||||
|
|
||||||
let mut ventry = FileMetaVersion::default();
|
let mut ventry = FileMetaVersion::default();
|
||||||
if fi.deleted {
|
if fi.deleted {
|
||||||
ventry.version_type = VersionType::Delete;
|
ventry.version_type = VersionType::Delete;
|
||||||
ventry.delete_marker = Some(MetaDeleteMarker {
|
ventry.delete_marker = Some(MetaDeleteMarker {
|
||||||
version_id: fi.version_id,
|
version_id: vid,
|
||||||
mod_time: fi.mod_time,
|
mod_time: fi.mod_time,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
@@ -689,8 +705,10 @@ impl FileMeta {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut found_index = None;
|
||||||
|
|
||||||
for (i, ver) in self.versions.iter().enumerate() {
|
for (i, ver) in self.versions.iter().enumerate() {
|
||||||
if ver.header.version_id != fi.version_id {
|
if ver.header.version_id != vid {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -701,7 +719,7 @@ impl FileMeta {
|
|||||||
let mut v = self.get_idx(i)?;
|
let mut v = self.get_idx(i)?;
|
||||||
if v.delete_marker.is_none() {
|
if v.delete_marker.is_none() {
|
||||||
v.delete_marker = Some(MetaDeleteMarker {
|
v.delete_marker = Some(MetaDeleteMarker {
|
||||||
version_id: fi.version_id,
|
version_id: vid,
|
||||||
mod_time: fi.mod_time,
|
mod_time: fi.mod_time,
|
||||||
meta_sys: HashMap::new(),
|
meta_sys: HashMap::new(),
|
||||||
});
|
});
|
||||||
@@ -767,7 +785,7 @@ impl FileMeta {
|
|||||||
self.versions.remove(i);
|
self.versions.remove(i);
|
||||||
|
|
||||||
if (fi.mark_deleted && fi.version_purge_status() != VersionPurgeStatusType::Complete)
|
if (fi.mark_deleted && fi.version_purge_status() != VersionPurgeStatusType::Complete)
|
||||||
|| (fi.deleted && fi.version_id.is_none())
|
|| (fi.deleted && vid == Some(Uuid::nil()))
|
||||||
{
|
{
|
||||||
self.add_version_filemata(ventry)?;
|
self.add_version_filemata(ventry)?;
|
||||||
}
|
}
|
||||||
@@ -803,18 +821,11 @@ impl FileMeta {
|
|||||||
|
|
||||||
return Ok(old_dir);
|
return Ok(old_dir);
|
||||||
}
|
}
|
||||||
|
found_index = Some(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut found_index = None;
|
|
||||||
for (i, version) in self.versions.iter().enumerate() {
|
|
||||||
if version.header.version_type == VersionType::Object && version.header.version_id == fi.version_id {
|
|
||||||
found_index = Some(i);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let Some(i) = found_index else {
|
let Some(i) = found_index else {
|
||||||
if fi.deleted {
|
if fi.deleted {
|
||||||
self.add_version_filemata(ventry)?;
|
self.add_version_filemata(ventry)?;
|
||||||
@@ -1521,7 +1532,8 @@ impl FileMetaVersionHeader {
|
|||||||
cur.read_exact(&mut buf)?;
|
cur.read_exact(&mut buf)?;
|
||||||
self.version_id = {
|
self.version_id = {
|
||||||
let id = Uuid::from_bytes(buf);
|
let id = Uuid::from_bytes(buf);
|
||||||
if id.is_nil() { None } else { Some(id) }
|
// if id.is_nil() { None } else { Some(id) }
|
||||||
|
Some(id)
|
||||||
};
|
};
|
||||||
|
|
||||||
// mod_time
|
// mod_time
|
||||||
@@ -1695,7 +1707,7 @@ impl MetaObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn into_fileinfo(&self, volume: &str, path: &str, all_parts: bool) -> FileInfo {
|
pub fn into_fileinfo(&self, volume: &str, path: &str, all_parts: bool) -> FileInfo {
|
||||||
let version_id = self.version_id.filter(|&vid| !vid.is_nil());
|
// let version_id = self.version_id.filter(|&vid| !vid.is_nil());
|
||||||
|
|
||||||
let parts = if all_parts {
|
let parts = if all_parts {
|
||||||
let mut parts = vec![ObjectPartInfo::default(); self.part_numbers.len()];
|
let mut parts = vec![ObjectPartInfo::default(); self.part_numbers.len()];
|
||||||
@@ -1799,7 +1811,7 @@ impl MetaObject {
|
|||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
|
|
||||||
FileInfo {
|
FileInfo {
|
||||||
version_id,
|
version_id: self.version_id,
|
||||||
erasure,
|
erasure,
|
||||||
data_dir: self.data_dir,
|
data_dir: self.data_dir,
|
||||||
mod_time: self.mod_time,
|
mod_time: self.mod_time,
|
||||||
|
|||||||
@@ -272,8 +272,7 @@ fn init_file_logging(config: &OtelConfig, logger_level: &str, is_production: boo
|
|||||||
if (current & !desired) != 0 {
|
if (current & !desired) != 0 {
|
||||||
if let Err(e) = fs::set_permissions(log_directory, Permissions::from_mode(desired)) {
|
if let Err(e) = fs::set_permissions(log_directory, Permissions::from_mode(desired)) {
|
||||||
return Err(TelemetryError::SetPermissions(format!(
|
return Err(TelemetryError::SetPermissions(format!(
|
||||||
"dir='{}', want={:#o}, have={:#o}, err={}",
|
"dir='{log_directory}', want={desired:#o}, have={current:#o}, err={e}"
|
||||||
log_directory, desired, current, e
|
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
// Second verification
|
// Second verification
|
||||||
@@ -281,15 +280,14 @@ fn init_file_logging(config: &OtelConfig, logger_level: &str, is_production: boo
|
|||||||
let after = meta2.permissions().mode() & 0o777;
|
let after = meta2.permissions().mode() & 0o777;
|
||||||
if after != desired {
|
if after != desired {
|
||||||
return Err(TelemetryError::SetPermissions(format!(
|
return Err(TelemetryError::SetPermissions(format!(
|
||||||
"dir='{}', want={:#o}, after={:#o}",
|
"dir='{log_directory}', want={desired:#o}, after={after:#o}"
|
||||||
log_directory, desired, after
|
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
return Err(TelemetryError::Io(format!("stat '{}' failed: {}", log_directory, e)));
|
return Err(TelemetryError::Io(format!("stat '{log_directory}' failed: {e}")));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -543,7 +543,7 @@ mod tests {
|
|||||||
*req.uri_mut() = Uri::from_parts(parts).unwrap();
|
*req.uri_mut() = Uri::from_parts(parts).unwrap();
|
||||||
|
|
||||||
let canonical_request = get_canonical_request(&req, &v4_ignored_headers, &get_hashed_payload(&req));
|
let canonical_request = get_canonical_request(&req, &v4_ignored_headers, &get_hashed_payload(&req));
|
||||||
println!("canonical_request: \n{}\n", canonical_request);
|
println!("canonical_request: \n{canonical_request}\n");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
canonical_request,
|
canonical_request,
|
||||||
concat!(
|
concat!(
|
||||||
@@ -562,7 +562,7 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let string_to_sign = get_string_to_sign_v4(t, region, &canonical_request, service);
|
let string_to_sign = get_string_to_sign_v4(t, region, &canonical_request, service);
|
||||||
println!("string_to_sign: \n{}\n", string_to_sign);
|
println!("string_to_sign: \n{string_to_sign}\n");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
string_to_sign,
|
string_to_sign,
|
||||||
concat!(
|
concat!(
|
||||||
@@ -576,7 +576,7 @@ mod tests {
|
|||||||
|
|
||||||
let signing_key = get_signing_key(secret_access_key, region, t, service);
|
let signing_key = get_signing_key(secret_access_key, region, t, service);
|
||||||
let signature = get_signature(signing_key, &string_to_sign);
|
let signature = get_signature(signing_key, &string_to_sign);
|
||||||
println!("signature: \n{}\n", signature);
|
println!("signature: \n{signature}\n");
|
||||||
assert_eq!(signature, "73fad2dfea0727e10a7179bf49150360a56f2e6b519c53999fd6e011152187d0");
|
assert_eq!(signature, "73fad2dfea0727e10a7179bf49150360a56f2e6b519c53999fd6e011152187d0");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -608,7 +608,7 @@ mod tests {
|
|||||||
|
|
||||||
println!("{:?}", req.uri().query());
|
println!("{:?}", req.uri().query());
|
||||||
let canonical_request = get_canonical_request(&req, &v4_ignored_headers, &get_hashed_payload(&req));
|
let canonical_request = get_canonical_request(&req, &v4_ignored_headers, &get_hashed_payload(&req));
|
||||||
println!("canonical_request: \n{}\n", canonical_request);
|
println!("canonical_request: \n{canonical_request}\n");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
canonical_request,
|
canonical_request,
|
||||||
concat!(
|
concat!(
|
||||||
@@ -627,7 +627,7 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let string_to_sign = get_string_to_sign_v4(t, region, &canonical_request, service);
|
let string_to_sign = get_string_to_sign_v4(t, region, &canonical_request, service);
|
||||||
println!("string_to_sign: \n{}\n", string_to_sign);
|
println!("string_to_sign: \n{string_to_sign}\n");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
string_to_sign,
|
string_to_sign,
|
||||||
concat!(
|
concat!(
|
||||||
@@ -641,7 +641,7 @@ mod tests {
|
|||||||
|
|
||||||
let signing_key = get_signing_key(secret_access_key, region, t, service);
|
let signing_key = get_signing_key(secret_access_key, region, t, service);
|
||||||
let signature = get_signature(signing_key, &string_to_sign);
|
let signature = get_signature(signing_key, &string_to_sign);
|
||||||
println!("signature: \n{}\n", signature);
|
println!("signature: \n{signature}\n");
|
||||||
assert_eq!(signature, "dfbed913d1982428f6224ee506431fc133dbcad184194c0cbf01bc517435788a");
|
assert_eq!(signature, "dfbed913d1982428f6224ee506431fc133dbcad184194c0cbf01bc517435788a");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -673,7 +673,7 @@ mod tests {
|
|||||||
|
|
||||||
println!("{:?}", req.uri().query());
|
println!("{:?}", req.uri().query());
|
||||||
let canonical_request = get_canonical_request(&req, &v4_ignored_headers, &get_hashed_payload(&req));
|
let canonical_request = get_canonical_request(&req, &v4_ignored_headers, &get_hashed_payload(&req));
|
||||||
println!("canonical_request: \n{}\n", canonical_request);
|
println!("canonical_request: \n{canonical_request}\n");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
canonical_request,
|
canonical_request,
|
||||||
concat!(
|
concat!(
|
||||||
@@ -692,7 +692,7 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let string_to_sign = get_string_to_sign_v4(t, region, &canonical_request, service);
|
let string_to_sign = get_string_to_sign_v4(t, region, &canonical_request, service);
|
||||||
println!("string_to_sign: \n{}\n", string_to_sign);
|
println!("string_to_sign: \n{string_to_sign}\n");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
string_to_sign,
|
string_to_sign,
|
||||||
concat!(
|
concat!(
|
||||||
@@ -706,7 +706,7 @@ mod tests {
|
|||||||
|
|
||||||
let signing_key = get_signing_key(secret_access_key, region, t, service);
|
let signing_key = get_signing_key(secret_access_key, region, t, service);
|
||||||
let signature = get_signature(signing_key, &string_to_sign);
|
let signature = get_signature(signing_key, &string_to_sign);
|
||||||
println!("signature: \n{}\n", signature);
|
println!("signature: \n{signature}\n");
|
||||||
assert_eq!(signature, "c7c7c6e12e5709c0c2ffc4707600a86c3cd261dd1de7409126a17f5b08c58dfa");
|
assert_eq!(signature, "c7c7c6e12e5709c0c2ffc4707600a86c3cd261dd1de7409126a17f5b08c58dfa");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -114,7 +114,7 @@ async fn async_main() -> Result<()> {
|
|||||||
let guard = match init_obs(Some(opt.clone().obs_endpoint)).await {
|
let guard = match init_obs(Some(opt.clone().obs_endpoint)).await {
|
||||||
Ok(g) => g,
|
Ok(g) => g,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
println!("Failed to initialize observability: {}", e);
|
println!("Failed to initialize observability: {e}");
|
||||||
return Err(Error::other(e));
|
return Err(Error::other(e));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1077,7 +1077,7 @@ impl S3 for FS {
|
|||||||
warn!("unable to restore transitioned bucket/object {}/{}: {}", bucket, object, err.to_string());
|
warn!("unable to restore transitioned bucket/object {}/{}: {}", bucket, object, err.to_string());
|
||||||
return Err(S3Error::with_message(
|
return Err(S3Error::with_message(
|
||||||
S3ErrorCode::Custom("ErrRestoreTransitionedObject".into()),
|
S3ErrorCode::Custom("ErrRestoreTransitionedObject".into()),
|
||||||
format!("unable to restore transitioned bucket/object {}/{}: {}", bucket, object, err),
|
format!("unable to restore transitioned bucket/object {bucket}/{object}: {err}"),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1329,7 +1329,7 @@ impl S3 for FS {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if is_dir_object(&object.object_name) && object.version_id.is_none() {
|
if is_dir_object(&object.object_name) && object.version_id.is_none() {
|
||||||
object.version_id = Some(Uuid::max());
|
object.version_id = Some(Uuid::nil());
|
||||||
}
|
}
|
||||||
|
|
||||||
if replicate_deletes {
|
if replicate_deletes {
|
||||||
|
|||||||
@@ -157,7 +157,7 @@ impl OperationHelper {
|
|||||||
.clone()
|
.clone()
|
||||||
.status(status)
|
.status(status)
|
||||||
.status_code(status_code)
|
.status_code(status_code)
|
||||||
.time_to_response(format!("{:.2?}", ttr))
|
.time_to_response(format!("{ttr:.2?}"))
|
||||||
.time_to_response_in_ns(ttr.as_nanos().to_string())
|
.time_to_response_in_ns(ttr.as_nanos().to_string())
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
|||||||
@@ -65,15 +65,12 @@ pub async fn del_opts(
|
|||||||
let vid = vid.map(|v| v.as_str().trim().to_owned());
|
let vid = vid.map(|v| v.as_str().trim().to_owned());
|
||||||
|
|
||||||
if let Some(ref id) = vid {
|
if let Some(ref id) = vid {
|
||||||
if let Err(err) = Uuid::parse_str(id.as_str()) {
|
if *id != Uuid::nil().to_string()
|
||||||
|
&& let Err(err) = Uuid::parse_str(id.as_str())
|
||||||
|
{
|
||||||
error!("del_opts: invalid version id: {} error: {}", id, err);
|
error!("del_opts: invalid version id: {} error: {}", id, err);
|
||||||
return Err(StorageError::InvalidVersionID(bucket.to_owned(), object.to_owned(), id.clone()));
|
return Err(StorageError::InvalidVersionID(bucket.to_owned(), object.to_owned(), id.clone()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if !versioned {
|
|
||||||
error!("del_opts: object not versioned: {}", object);
|
|
||||||
return Err(StorageError::InvalidArgument(bucket.to_owned(), object.to_owned(), id.clone()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut opts = put_opts_from_headers(headers, metadata.clone()).map_err(|err| {
|
let mut opts = put_opts_from_headers(headers, metadata.clone()).map_err(|err| {
|
||||||
@@ -83,7 +80,7 @@ pub async fn del_opts(
|
|||||||
|
|
||||||
opts.version_id = {
|
opts.version_id = {
|
||||||
if is_dir_object(object) && vid.is_none() {
|
if is_dir_object(object) && vid.is_none() {
|
||||||
Some(Uuid::max().to_string())
|
Some(Uuid::nil().to_string())
|
||||||
} else {
|
} else {
|
||||||
vid
|
vid
|
||||||
}
|
}
|
||||||
@@ -113,13 +110,11 @@ pub async fn get_opts(
|
|||||||
let vid = vid.map(|v| v.as_str().trim().to_owned());
|
let vid = vid.map(|v| v.as_str().trim().to_owned());
|
||||||
|
|
||||||
if let Some(ref id) = vid {
|
if let Some(ref id) = vid {
|
||||||
if let Err(_err) = Uuid::parse_str(id.as_str()) {
|
if *id != Uuid::nil().to_string()
|
||||||
|
&& let Err(_err) = Uuid::parse_str(id.as_str())
|
||||||
|
{
|
||||||
return Err(StorageError::InvalidVersionID(bucket.to_owned(), object.to_owned(), id.clone()));
|
return Err(StorageError::InvalidVersionID(bucket.to_owned(), object.to_owned(), id.clone()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if !versioned {
|
|
||||||
return Err(StorageError::InvalidArgument(bucket.to_owned(), object.to_owned(), id.clone()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut opts = get_default_opts(headers, HashMap::new(), false)
|
let mut opts = get_default_opts(headers, HashMap::new(), false)
|
||||||
@@ -127,7 +122,7 @@ pub async fn get_opts(
|
|||||||
|
|
||||||
opts.version_id = {
|
opts.version_id = {
|
||||||
if is_dir_object(object) && vid.is_none() {
|
if is_dir_object(object) && vid.is_none() {
|
||||||
Some(Uuid::max().to_string())
|
Some(Uuid::nil().to_string())
|
||||||
} else {
|
} else {
|
||||||
vid
|
vid
|
||||||
}
|
}
|
||||||
@@ -189,13 +184,11 @@ pub async fn put_opts(
|
|||||||
let vid = vid.map(|v| v.as_str().trim().to_owned());
|
let vid = vid.map(|v| v.as_str().trim().to_owned());
|
||||||
|
|
||||||
if let Some(ref id) = vid {
|
if let Some(ref id) = vid {
|
||||||
if let Err(_err) = Uuid::parse_str(id.as_str()) {
|
if *id != Uuid::nil().to_string()
|
||||||
|
&& let Err(_err) = Uuid::parse_str(id.as_str())
|
||||||
|
{
|
||||||
return Err(StorageError::InvalidVersionID(bucket.to_owned(), object.to_owned(), id.clone()));
|
return Err(StorageError::InvalidVersionID(bucket.to_owned(), object.to_owned(), id.clone()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if !versioned {
|
|
||||||
return Err(StorageError::InvalidArgument(bucket.to_owned(), object.to_owned(), id.clone()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut opts = put_opts_from_headers(headers, metadata)
|
let mut opts = put_opts_from_headers(headers, metadata)
|
||||||
@@ -203,7 +196,7 @@ pub async fn put_opts(
|
|||||||
|
|
||||||
opts.version_id = {
|
opts.version_id = {
|
||||||
if is_dir_object(object) && vid.is_none() {
|
if is_dir_object(object) && vid.is_none() {
|
||||||
Some(Uuid::max().to_string())
|
Some(Uuid::nil().to_string())
|
||||||
} else {
|
} else {
|
||||||
vid
|
vid
|
||||||
}
|
}
|
||||||
@@ -603,7 +596,7 @@ mod tests {
|
|||||||
|
|
||||||
assert!(result.is_ok());
|
assert!(result.is_ok());
|
||||||
let opts = result.unwrap();
|
let opts = result.unwrap();
|
||||||
assert_eq!(opts.version_id, Some(Uuid::max().to_string()));
|
assert_eq!(opts.version_id, Some(Uuid::nil().to_string()));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -676,7 +669,7 @@ mod tests {
|
|||||||
|
|
||||||
assert!(result.is_ok());
|
assert!(result.is_ok());
|
||||||
let opts = result.unwrap();
|
let opts = result.unwrap();
|
||||||
assert_eq!(opts.version_id, Some(Uuid::max().to_string()));
|
assert_eq!(opts.version_id, Some(Uuid::nil().to_string()));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -720,7 +713,7 @@ mod tests {
|
|||||||
|
|
||||||
assert!(result.is_ok());
|
assert!(result.is_ok());
|
||||||
let opts = result.unwrap();
|
let opts = result.unwrap();
|
||||||
assert_eq!(opts.version_id, Some(Uuid::max().to_string()));
|
assert_eq!(opts.version_id, Some(Uuid::nil().to_string()));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
|||||||
Reference in New Issue
Block a user