mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-21 20:06:37 +00:00
Fix/ilm (#721)
* fix tip remote tier error * fix transitioned_object * fix filemeta * add GCS R2 * add aliyun tencent huaweicloud azure gcs r2 backend tier * fix signer * change azure to s3 Co-authored-by: houseme <housemecn@gmail.com> Co-authored-by: loverustfs <155562731+loverustfs@users.noreply.github.com>
This commit is contained in:
@@ -31,13 +31,15 @@ use crate::disk::{
|
||||
use crate::erasure_coding;
|
||||
use crate::erasure_coding::bitrot_verify;
|
||||
use crate::error::{Error, Result, is_err_version_not_found};
|
||||
use crate::error::{ObjectApiError, is_err_object_not_found};
|
||||
use crate::error::{GenericError, ObjectApiError, is_err_object_not_found};
|
||||
use crate::global::{GLOBAL_LocalNodeName, GLOBAL_TierConfigMgr};
|
||||
use crate::store_api::ListObjectVersionsInfo;
|
||||
use crate::store_api::{ListPartsInfo, ObjectOptions, ObjectToDelete};
|
||||
use crate::store_api::{ObjectInfoOrErr, WalkOptions};
|
||||
use crate::{
|
||||
bucket::lifecycle::bucket_lifecycle_ops::{gen_transition_objname, get_transitioned_object_reader, put_restore_opts},
|
||||
bucket::lifecycle::bucket_lifecycle_ops::{
|
||||
LifecycleOps, gen_transition_objname, get_transitioned_object_reader, put_restore_opts,
|
||||
},
|
||||
cache_value::metacache_set::{ListPathRawOptions, list_path_raw},
|
||||
config::{GLOBAL_STORAGE_CLASS, storageclass},
|
||||
disk::{
|
||||
@@ -96,7 +98,7 @@ use std::{
|
||||
};
|
||||
use time::OffsetDateTime;
|
||||
use tokio::{
|
||||
io::AsyncWrite,
|
||||
io::{AsyncReadExt, AsyncWrite, AsyncWriteExt, BufReader},
|
||||
sync::{RwLock, broadcast},
|
||||
};
|
||||
use tokio::{
|
||||
@@ -3419,7 +3421,7 @@ impl SetDisks {
|
||||
oi.user_defined.remove(X_AMZ_RESTORE.as_str());
|
||||
|
||||
let version_id = oi.version_id.map(|v| v.to_string());
|
||||
let obj = self
|
||||
let _obj = self
|
||||
.copy_object(
|
||||
bucket,
|
||||
object,
|
||||
@@ -3435,8 +3437,7 @@ impl SetDisks {
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.await;
|
||||
obj?;
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -3536,7 +3537,10 @@ impl ObjectIO for SetDisks {
|
||||
return Ok(reader);
|
||||
}
|
||||
|
||||
// TODO: remote
|
||||
if object_info.is_remote() {
|
||||
let gr = get_transitioned_object_reader(bucket, object, &range, &h, &object_info, opts).await?;
|
||||
return Ok(gr);
|
||||
}
|
||||
|
||||
let (rd, wd) = tokio::io::duplex(DEFAULT_READ_BUFFER_SIZE);
|
||||
|
||||
@@ -4565,7 +4569,7 @@ impl StorageAPI for SetDisks {
|
||||
let tgt_client = match tier_config_mgr.get_driver(&opts.transition.tier).await {
|
||||
Ok(client) => client,
|
||||
Err(err) => {
|
||||
return Err(Error::other(err.to_string()));
|
||||
return Err(Error::other(format!("remote tier error: {}", err)));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -4594,10 +4598,10 @@ impl StorageAPI for SetDisks {
|
||||
// Normalize ETags by removing quotes before comparison (PR #592 compatibility)
|
||||
let transition_etag = rustfs_utils::path::trim_etag(&opts.transition.etag);
|
||||
let stored_etag = rustfs_utils::path::trim_etag(&get_raw_etag(&fi.metadata));
|
||||
if !opts.mod_time.expect("err").unix_timestamp() == fi.mod_time.as_ref().expect("err").unix_timestamp()
|
||||
if opts.mod_time.expect("err").unix_timestamp() != fi.mod_time.as_ref().expect("err").unix_timestamp()
|
||||
|| transition_etag != stored_etag
|
||||
{
|
||||
return Err(to_object_err(Error::from(DiskError::FileNotFound), vec![bucket, object]));
|
||||
return Err(to_object_err(Error::other(DiskError::FileNotFound), vec![bucket, object]));
|
||||
}
|
||||
if fi.transition_status == TRANSITION_COMPLETE {
|
||||
return Ok(());
|
||||
@@ -4699,7 +4703,7 @@ impl StorageAPI for SetDisks {
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "debug", skip(self))]
|
||||
async fn restore_transitioned_object(&self, bucket: &str, object: &str, opts: &ObjectOptions) -> Result<()> {
|
||||
async fn restore_transitioned_object(self: Arc<Self>, bucket: &str, object: &str, opts: &ObjectOptions) -> Result<()> {
|
||||
// Acquire write-lock early for the restore operation
|
||||
// if !opts.no_lock {
|
||||
// let guard_opt = self
|
||||
@@ -4711,6 +4715,7 @@ impl StorageAPI for SetDisks {
|
||||
// }
|
||||
// _lock_guard = guard_opt;
|
||||
// }
|
||||
let self_ = self.clone();
|
||||
let set_restore_header_fn = async move |oi: &mut ObjectInfo, rerr: Option<Error>| -> Result<()> {
|
||||
if rerr.is_none() {
|
||||
return Ok(());
|
||||
@@ -4719,54 +4724,79 @@ impl StorageAPI for SetDisks {
|
||||
Err(rerr.unwrap())
|
||||
};
|
||||
let mut oi = ObjectInfo::default();
|
||||
let fi = self.get_object_fileinfo(bucket, object, opts, true).await;
|
||||
let fi = self_.clone().get_object_fileinfo(bucket, object, opts, true).await;
|
||||
if let Err(err) = fi {
|
||||
return set_restore_header_fn(&mut oi, Some(to_object_err(err, vec![bucket, object]))).await;
|
||||
}
|
||||
let (actual_fi, _, _) = fi.unwrap();
|
||||
|
||||
oi = ObjectInfo::from_file_info(&actual_fi, bucket, object, opts.versioned || opts.version_suspended);
|
||||
let ropts = put_restore_opts(bucket, object, &opts.transition.restore_request, &oi);
|
||||
/*if oi.parts.len() == 1 {
|
||||
let mut rs: HTTPRangeSpec;
|
||||
let gr = get_transitioned_object_reader(bucket, object, rs, HeaderMap::new(), oi, opts);
|
||||
//if err != nil {
|
||||
// return set_restore_header_fn(&mut oi, Some(toObjectErr(err, bucket, object)));
|
||||
//}
|
||||
let hash_reader = HashReader::new(gr, gr.obj_info.size, "", "", gr.obj_info.size);
|
||||
let p_reader = PutObjReader::new(StreamingBlob::from(Box::pin(hash_reader)), hash_reader.size());
|
||||
if let Err(err) = self.put_object(bucket, object, &mut p_reader, &ropts).await {
|
||||
return set_restore_header_fn(&mut oi, Some(to_object_err(err, vec![bucket, object])));
|
||||
let ropts = put_restore_opts(bucket, object, &opts.transition.restore_request, &oi).await?;
|
||||
if oi.parts.len() == 1 {
|
||||
let rs: Option<HTTPRangeSpec> = None;
|
||||
let gr = get_transitioned_object_reader(bucket, object, &rs, &HeaderMap::new(), &oi, opts).await;
|
||||
if let Err(err) = gr {
|
||||
return set_restore_header_fn(&mut oi, Some(to_object_err(err.into(), vec![bucket, object]))).await;
|
||||
}
|
||||
let gr = gr.unwrap();
|
||||
let reader = BufReader::new(gr.stream);
|
||||
let hash_reader = HashReader::new(
|
||||
Box::new(WarpReader::new(reader)),
|
||||
gr.object_info.size,
|
||||
gr.object_info.size,
|
||||
None,
|
||||
None,
|
||||
false,
|
||||
)?;
|
||||
let mut p_reader = PutObjReader::new(hash_reader);
|
||||
if let Err(err) = self_.clone().put_object(bucket, object, &mut p_reader, &ropts).await {
|
||||
return set_restore_header_fn(&mut oi, Some(to_object_err(err, vec![bucket, object]))).await;
|
||||
} else {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
let res = self.new_multipart_upload(bucket, object, &ropts).await?;
|
||||
let res = self_.clone().new_multipart_upload(bucket, object, &ropts).await?;
|
||||
//if err != nil {
|
||||
// return set_restore_header_fn(&mut oi, err);
|
||||
// return set_restore_header_fn(&mut oi, err).await;
|
||||
//}
|
||||
|
||||
let mut uploaded_parts: Vec<CompletePart> = vec![];
|
||||
let mut rs: HTTPRangeSpec;
|
||||
let gr = get_transitioned_object_reader(bucket, object, rs, HeaderMap::new(), oi, opts).await?;
|
||||
//if err != nil {
|
||||
// return set_restore_header_fn(&mut oi, err);
|
||||
//}
|
||||
let rs: Option<HTTPRangeSpec> = None;
|
||||
let gr = get_transitioned_object_reader(bucket, object, &rs, &HeaderMap::new(), &oi, opts).await;
|
||||
if let Err(err) = gr {
|
||||
return set_restore_header_fn(&mut oi, Some(StorageError::Io(err))).await;
|
||||
}
|
||||
let gr = gr.unwrap();
|
||||
|
||||
for part_info in oi.parts {
|
||||
//let hr = HashReader::new(LimitReader(gr, part_info.size), part_info.size, "", "", part_info.size);
|
||||
let hr = HashReader::new(gr, part_info.size as i64, part_info.size as i64, None, false);
|
||||
//if err != nil {
|
||||
// return set_restore_header_fn(&mut oi, err);
|
||||
//}
|
||||
let mut p_reader = PutObjReader::new(hr, hr.size());
|
||||
let p_info = self.put_object_part(bucket, object, &res.upload_id, part_info.number, &mut p_reader, &ObjectOptions::default()).await?;
|
||||
for part_info in &oi.parts {
|
||||
let reader = BufReader::new(Cursor::new(vec![] /*gr.stream*/));
|
||||
let hash_reader = HashReader::new(
|
||||
Box::new(WarpReader::new(reader)),
|
||||
part_info.size as i64,
|
||||
part_info.size as i64,
|
||||
None,
|
||||
None,
|
||||
false,
|
||||
)?;
|
||||
let mut p_reader = PutObjReader::new(hash_reader);
|
||||
let p_info = self_
|
||||
.clone()
|
||||
.put_object_part(bucket, object, &res.upload_id, part_info.number, &mut p_reader, &ObjectOptions::default())
|
||||
.await?;
|
||||
//if let Err(err) = p_info {
|
||||
// return set_restore_header_fn(&mut oi, err);
|
||||
// return set_restore_header_fn(&mut oi, err).await;
|
||||
//}
|
||||
if p_info.size != part_info.size {
|
||||
return set_restore_header_fn(&mut oi, Some(Error::from(ObjectApiError::InvalidObjectState(GenericError{bucket: bucket.to_string(), object: object.to_string(), ..Default::default()}))));
|
||||
return set_restore_header_fn(
|
||||
&mut oi,
|
||||
Some(Error::other(ObjectApiError::InvalidObjectState(GenericError {
|
||||
bucket: bucket.to_string(),
|
||||
object: object.to_string(),
|
||||
..Default::default()
|
||||
}))),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
uploaded_parts.push(CompletePart {
|
||||
part_num: p_info.part_num,
|
||||
@@ -4778,12 +4808,22 @@ impl StorageAPI for SetDisks {
|
||||
checksum_crc64nvme: None,
|
||||
});
|
||||
}
|
||||
if let Err(err) = self.complete_multipart_upload(bucket, object, &res.upload_id, uploaded_parts, &ObjectOptions {
|
||||
mod_time: oi.mod_time,
|
||||
..Default::default()
|
||||
}).await {
|
||||
set_restore_header_fn(&mut oi, Some(err));
|
||||
}*/
|
||||
if let Err(err) = self_
|
||||
.clone()
|
||||
.complete_multipart_upload(
|
||||
bucket,
|
||||
object,
|
||||
&res.upload_id,
|
||||
uploaded_parts,
|
||||
&ObjectOptions {
|
||||
mod_time: oi.mod_time,
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.await
|
||||
{
|
||||
return set_restore_header_fn(&mut oi, Some(err)).await;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user