mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-20 19:42:17 +00:00
refactor: improve object listing and version handling
- Refactor find_version_index to accept Uuid directly instead of string - Split from_meta_cache_entries_sorted into separate methods for versions and infos - Add support for after_version_id filtering in version listing - Fix S3 error code for replication configuration not found - Improve error handling and logging levels - Clean up import statements and remove debug code
This commit is contained in:
@@ -461,13 +461,7 @@ pub struct FileInfoVersions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl FileInfoVersions {
|
impl FileInfoVersions {
|
||||||
pub fn find_version_index(&self, v: &str) -> Option<usize> {
|
pub fn find_version_index(&self, vid: Uuid) -> Option<usize> {
|
||||||
if v.is_empty() {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
let vid = Uuid::parse_str(v).unwrap_or_default();
|
|
||||||
|
|
||||||
self.versions.iter().position(|v| v.version_id == Some(vid))
|
self.versions.iter().position(|v| v.version_id == Some(vid))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2006,11 +2006,7 @@ impl MetaObject {
|
|||||||
if *status == TRANSITION_COMPLETE.as_bytes().to_vec() {
|
if *status == TRANSITION_COMPLETE.as_bytes().to_vec() {
|
||||||
let vid = Uuid::parse_str(&fi.tier_free_version_id());
|
let vid = Uuid::parse_str(&fi.tier_free_version_id());
|
||||||
if let Err(err) = vid {
|
if let Err(err) = vid {
|
||||||
panic!(
|
panic!("Invalid Tier Object delete marker versionId {} {}", fi.tier_free_version_id(), err);
|
||||||
"Invalid Tier Object delete marker versionId {} {}",
|
|
||||||
fi.tier_free_version_id(),
|
|
||||||
err
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
let vid = vid.unwrap();
|
let vid = vid.unwrap();
|
||||||
let mut free_entry = FileMetaVersion {
|
let mut free_entry = FileMetaVersion {
|
||||||
|
|||||||
@@ -1,19 +1,19 @@
|
|||||||
use crate::OtelConfig;
|
use crate::OtelConfig;
|
||||||
use flexi_logger::{style, Age, Cleanup, Criterion, DeferredNow, FileSpec, LogSpecification, Naming, Record, WriteMode};
|
use flexi_logger::{Age, Cleanup, Criterion, DeferredNow, FileSpec, LogSpecification, Naming, Record, WriteMode, style};
|
||||||
use nu_ansi_term::Color;
|
use nu_ansi_term::Color;
|
||||||
use opentelemetry::trace::TracerProvider;
|
use opentelemetry::trace::TracerProvider;
|
||||||
use opentelemetry::{global, KeyValue};
|
use opentelemetry::{KeyValue, global};
|
||||||
use opentelemetry_appender_tracing::layer::OpenTelemetryTracingBridge;
|
use opentelemetry_appender_tracing::layer::OpenTelemetryTracingBridge;
|
||||||
use opentelemetry_otlp::WithExportConfig;
|
use opentelemetry_otlp::WithExportConfig;
|
||||||
use opentelemetry_sdk::logs::SdkLoggerProvider;
|
use opentelemetry_sdk::logs::SdkLoggerProvider;
|
||||||
use opentelemetry_sdk::{
|
use opentelemetry_sdk::{
|
||||||
|
Resource,
|
||||||
metrics::{MeterProviderBuilder, PeriodicReader, SdkMeterProvider},
|
metrics::{MeterProviderBuilder, PeriodicReader, SdkMeterProvider},
|
||||||
trace::{RandomIdGenerator, Sampler, SdkTracerProvider},
|
trace::{RandomIdGenerator, Sampler, SdkTracerProvider},
|
||||||
Resource,
|
|
||||||
};
|
};
|
||||||
use opentelemetry_semantic_conventions::{
|
use opentelemetry_semantic_conventions::{
|
||||||
attribute::{DEPLOYMENT_ENVIRONMENT_NAME, NETWORK_LOCAL_ADDRESS, SERVICE_VERSION as OTEL_SERVICE_VERSION},
|
|
||||||
SCHEMA_URL,
|
SCHEMA_URL,
|
||||||
|
attribute::{DEPLOYMENT_ENVIRONMENT_NAME, NETWORK_LOCAL_ADDRESS, SERVICE_VERSION as OTEL_SERVICE_VERSION},
|
||||||
};
|
};
|
||||||
use rustfs_config::{
|
use rustfs_config::{
|
||||||
APP_NAME, DEFAULT_LOG_DIR, DEFAULT_LOG_KEEP_FILES, DEFAULT_LOG_LEVEL, ENVIRONMENT, METER_INTERVAL, SAMPLE_RATIO,
|
APP_NAME, DEFAULT_LOG_DIR, DEFAULT_LOG_KEEP_FILES, DEFAULT_LOG_LEVEL, ENVIRONMENT, METER_INTERVAL, SAMPLE_RATIO,
|
||||||
@@ -28,7 +28,7 @@ use tracing_error::ErrorLayer;
|
|||||||
use tracing_opentelemetry::{MetricsLayer, OpenTelemetryLayer};
|
use tracing_opentelemetry::{MetricsLayer, OpenTelemetryLayer};
|
||||||
use tracing_subscriber::fmt::format::FmtSpan;
|
use tracing_subscriber::fmt::format::FmtSpan;
|
||||||
use tracing_subscriber::fmt::time::LocalTime;
|
use tracing_subscriber::fmt::time::LocalTime;
|
||||||
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, EnvFilter, Layer};
|
use tracing_subscriber::{EnvFilter, Layer, layer::SubscriberExt, util::SubscriberInitExt};
|
||||||
|
|
||||||
/// A guard object that manages the lifecycle of OpenTelemetry components.
|
/// A guard object that manages the lifecycle of OpenTelemetry components.
|
||||||
///
|
///
|
||||||
|
|||||||
@@ -40,14 +40,12 @@ pub fn get_info(p: impl AsRef<Path>) -> std::io::Result<DiskInfo> {
|
|||||||
let free = unsafe { *lp_total_number_of_free_bytes.QuadPart() };
|
let free = unsafe { *lp_total_number_of_free_bytes.QuadPart() };
|
||||||
|
|
||||||
if free > total {
|
if free > total {
|
||||||
return Err(Error::other(
|
return Err(Error::other(format!(
|
||||||
format!(
|
"detected free space ({}) > total drive space ({}), fs corruption at ({}). please run 'fsck'",
|
||||||
"detected free space ({}) > total drive space ({}), fs corruption at ({}). please run 'fsck'",
|
free,
|
||||||
free,
|
total,
|
||||||
total,
|
p.as_ref().display()
|
||||||
p.as_ref().display()
|
)));
|
||||||
),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut lp_sectors_per_cluster: DWORD = 0;
|
let mut lp_sectors_per_cluster: DWORD = 0;
|
||||||
|
|||||||
@@ -65,4 +65,4 @@ impl Stream for RetryTimer {
|
|||||||
|
|
||||||
pub fn new_retry_timer(_max_retry: i32, _base_sleep: Duration, _max_sleep: Duration, _jitter: f64) -> Vec<i32> {
|
pub fn new_retry_timer(_max_retry: i32, _base_sleep: Duration, _max_sleep: Duration, _jitter: f64) -> Vec<i32> {
|
||||||
todo!();
|
todo!();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -198,7 +198,8 @@ impl Lifecycle for BucketLifecycleConfiguration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let rule_prefix = rule.prefix.as_ref().expect("err!");
|
let rule_prefix = rule.prefix.as_ref().expect("err!");
|
||||||
if prefix.len() > 0 && rule_prefix.len() > 0 && !prefix.starts_with(rule_prefix) && !rule_prefix.starts_with(&prefix) {
|
if prefix.len() > 0 && rule_prefix.len() > 0 && !prefix.starts_with(rule_prefix) && !rule_prefix.starts_with(&prefix)
|
||||||
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -425,7 +426,8 @@ impl Lifecycle for BucketLifecycleConfiguration {
|
|||||||
if !obj.is_latest {
|
if !obj.is_latest {
|
||||||
if let Some(ref noncurrent_version_transitions) = rule.noncurrent_version_transitions {
|
if let Some(ref noncurrent_version_transitions) = rule.noncurrent_version_transitions {
|
||||||
if let Some(ref storage_class) = noncurrent_version_transitions[0].storage_class {
|
if let Some(ref storage_class) = noncurrent_version_transitions[0].storage_class {
|
||||||
if storage_class.as_str() != "" && !obj.delete_marker && obj.transition_status != TRANSITION_COMPLETE {
|
if storage_class.as_str() != "" && !obj.delete_marker && obj.transition_status != TRANSITION_COMPLETE
|
||||||
|
{
|
||||||
let due = rule.noncurrent_version_transitions.as_ref().unwrap()[0].next_due(obj);
|
let due = rule.noncurrent_version_transitions.as_ref().unwrap()[0].next_due(obj);
|
||||||
if due.is_some()
|
if due.is_some()
|
||||||
&& (now.unix_timestamp() == 0 || now.unix_timestamp() > due.unwrap().unix_timestamp())
|
&& (now.unix_timestamp() == 0 || now.unix_timestamp() > due.unwrap().unix_timestamp())
|
||||||
@@ -452,7 +454,9 @@ impl Lifecycle for BucketLifecycleConfiguration {
|
|||||||
if let Some(ref expiration) = rule.expiration {
|
if let Some(ref expiration) = rule.expiration {
|
||||||
if let Some(ref date) = expiration.date {
|
if let Some(ref date) = expiration.date {
|
||||||
let date0 = OffsetDateTime::from(date.clone());
|
let date0 = OffsetDateTime::from(date.clone());
|
||||||
if date0.unix_timestamp() != 0 && (now.unix_timestamp() == 0 || now.unix_timestamp() > date0.unix_timestamp()) {
|
if date0.unix_timestamp() != 0
|
||||||
|
&& (now.unix_timestamp() == 0 || now.unix_timestamp() > date0.unix_timestamp())
|
||||||
|
{
|
||||||
events.push(Event {
|
events.push(Event {
|
||||||
action: IlmAction::DeleteAction,
|
action: IlmAction::DeleteAction,
|
||||||
rule_id: rule.id.clone().expect("err!"),
|
rule_id: rule.id.clone().expect("err!"),
|
||||||
|
|||||||
@@ -4690,8 +4690,7 @@ impl StorageAPI for SetDisks {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let _ = self.add_partial(bucket, object, opts.version_id.as_ref().expect("err"))
|
let _ = self.add_partial(bucket, object, opts.version_id.as_ref().expect("err")).await;
|
||||||
.await;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -567,7 +567,92 @@ impl ObjectInfo {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn from_meta_cache_entries_sorted(
|
pub async fn from_meta_cache_entries_sorted_versions(
|
||||||
|
entries: &MetaCacheEntriesSorted,
|
||||||
|
bucket: &str,
|
||||||
|
prefix: &str,
|
||||||
|
delimiter: Option<String>,
|
||||||
|
after_version_id: Option<Uuid>,
|
||||||
|
) -> Vec<ObjectInfo> {
|
||||||
|
let vcfg = get_versioning_config(bucket).await.ok();
|
||||||
|
let mut objects = Vec::with_capacity(entries.entries().len());
|
||||||
|
let mut prev_prefix = "";
|
||||||
|
for entry in entries.entries() {
|
||||||
|
if entry.is_object() {
|
||||||
|
if let Some(delimiter) = &delimiter {
|
||||||
|
if let Some(idx) = entry.name.trim_start_matches(prefix).find(delimiter) {
|
||||||
|
let idx = prefix.len() + idx + delimiter.len();
|
||||||
|
if let Some(curr_prefix) = entry.name.get(0..idx) {
|
||||||
|
if curr_prefix == prev_prefix {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
prev_prefix = curr_prefix;
|
||||||
|
|
||||||
|
objects.push(ObjectInfo {
|
||||||
|
is_dir: true,
|
||||||
|
bucket: bucket.to_owned(),
|
||||||
|
name: curr_prefix.to_owned(),
|
||||||
|
..Default::default()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let file_infos = match entry.file_info_versions(bucket) {
|
||||||
|
Ok(res) => res,
|
||||||
|
Err(err) => {
|
||||||
|
warn!("file_info_versions err {:?}", err);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let versions = if let Some(vid) = after_version_id {
|
||||||
|
if let Some(idx) = file_infos.find_version_index(vid) {
|
||||||
|
&file_infos.versions[idx + 1..]
|
||||||
|
} else {
|
||||||
|
&file_infos.versions
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
&file_infos.versions
|
||||||
|
};
|
||||||
|
|
||||||
|
for fi in versions.iter() {
|
||||||
|
// TODO:VersionPurgeStatus
|
||||||
|
let versioned = vcfg.clone().map(|v| v.0.versioned(&entry.name)).unwrap_or_default();
|
||||||
|
objects.push(ObjectInfo::from_file_info(fi, bucket, &entry.name, versioned));
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if entry.is_dir() {
|
||||||
|
if let Some(delimiter) = &delimiter {
|
||||||
|
if let Some(idx) = entry.name.trim_start_matches(prefix).find(delimiter) {
|
||||||
|
let idx = prefix.len() + idx + delimiter.len();
|
||||||
|
if let Some(curr_prefix) = entry.name.get(0..idx) {
|
||||||
|
if curr_prefix == prev_prefix {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
prev_prefix = curr_prefix;
|
||||||
|
|
||||||
|
objects.push(ObjectInfo {
|
||||||
|
is_dir: true,
|
||||||
|
bucket: bucket.to_owned(),
|
||||||
|
name: curr_prefix.to_owned(),
|
||||||
|
..Default::default()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
objects
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn from_meta_cache_entries_sorted_infos(
|
||||||
entries: &MetaCacheEntriesSorted,
|
entries: &MetaCacheEntriesSorted,
|
||||||
bucket: &str,
|
bucket: &str,
|
||||||
prefix: &str,
|
prefix: &str,
|
||||||
@@ -599,11 +684,18 @@ impl ObjectInfo {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Ok(fi) = entry.to_fileinfo(bucket) {
|
let fi = match entry.to_fileinfo(bucket) {
|
||||||
// TODO:VersionPurgeStatus
|
Ok(res) => res,
|
||||||
let versioned = vcfg.clone().map(|v| v.0.versioned(&entry.name)).unwrap_or_default();
|
Err(err) => {
|
||||||
objects.push(ObjectInfo::from_file_info(&fi, bucket, &entry.name, versioned));
|
warn!("file_info_versions err {:?}", err);
|
||||||
}
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO:VersionPurgeStatus
|
||||||
|
let versioned = vcfg.clone().map(|v| v.0.versioned(&entry.name)).unwrap_or_default();
|
||||||
|
objects.push(ObjectInfo::from_file_info(&fi, bucket, &entry.name, versioned));
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ use std::collections::HashMap;
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tokio::sync::broadcast::{self, Receiver as B_Receiver};
|
use tokio::sync::broadcast::{self, Receiver as B_Receiver};
|
||||||
use tokio::sync::mpsc::{self, Receiver, Sender};
|
use tokio::sync::mpsc::{self, Receiver, Sender};
|
||||||
use tracing::{error, warn};
|
use tracing::{error, info};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
const MAX_OBJECT_LIST: i32 = 1000;
|
const MAX_OBJECT_LIST: i32 = 1000;
|
||||||
@@ -246,8 +246,6 @@ impl ECStore {
|
|||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
// warn!("list_objects_generic opts {:?}", &opts);
|
|
||||||
|
|
||||||
// use get
|
// use get
|
||||||
if !opts.prefix.is_empty() && opts.limit == 1 && opts.marker.is_none() {
|
if !opts.prefix.is_empty() && opts.limit == 1 && opts.marker.is_none() {
|
||||||
match self
|
match self
|
||||||
@@ -295,7 +293,7 @@ impl ECStore {
|
|||||||
|
|
||||||
// contextCanceled
|
// contextCanceled
|
||||||
|
|
||||||
let mut get_objects = ObjectInfo::from_meta_cache_entries_sorted(
|
let mut get_objects = ObjectInfo::from_meta_cache_entries_sorted_infos(
|
||||||
&list_result.entries.unwrap_or_default(),
|
&list_result.entries.unwrap_or_default(),
|
||||||
bucket,
|
bucket,
|
||||||
prefix,
|
prefix,
|
||||||
@@ -364,10 +362,15 @@ impl ECStore {
|
|||||||
max_keys: i32,
|
max_keys: i32,
|
||||||
) -> Result<ListObjectVersionsInfo> {
|
) -> Result<ListObjectVersionsInfo> {
|
||||||
if marker.is_none() && version_marker.is_some() {
|
if marker.is_none() && version_marker.is_some() {
|
||||||
warn!("inner_list_object_versions: marker is none and version_marker is some");
|
|
||||||
return Err(StorageError::NotImplemented);
|
return Err(StorageError::NotImplemented);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let version_marker = if let Some(marker) = version_marker {
|
||||||
|
Some(Uuid::parse_str(&marker)?)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
// if marker set, limit +1
|
// if marker set, limit +1
|
||||||
let opts = ListPathOptions {
|
let opts = ListPathOptions {
|
||||||
bucket: bucket.to_owned(),
|
bucket: bucket.to_owned(),
|
||||||
@@ -399,11 +402,12 @@ impl ECStore {
|
|||||||
result.forward_past(opts.marker);
|
result.forward_past(opts.marker);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut get_objects = ObjectInfo::from_meta_cache_entries_sorted(
|
let mut get_objects = ObjectInfo::from_meta_cache_entries_sorted_versions(
|
||||||
&list_result.entries.unwrap_or_default(),
|
&list_result.entries.unwrap_or_default(),
|
||||||
bucket,
|
bucket,
|
||||||
prefix,
|
prefix,
|
||||||
delimiter.clone(),
|
delimiter.clone(),
|
||||||
|
version_marker,
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
@@ -1068,7 +1072,7 @@ async fn merge_entry_channels(
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ = rx.recv()=>{
|
_ = rx.recv()=>{
|
||||||
warn!("merge_entry_channels rx.recv() cancel");
|
info!("merge_entry_channels rx.recv() cancel");
|
||||||
return Ok(())
|
return Ok(())
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1931,13 +1931,22 @@ impl S3 for FS {
|
|||||||
let rcfg = match metadata_sys::get_replication_config(&bucket).await {
|
let rcfg = match metadata_sys::get_replication_config(&bucket).await {
|
||||||
Ok((cfg, _created)) => Some(cfg),
|
Ok((cfg, _created)) => Some(cfg),
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
|
if err == StorageError::ConfigNotFound {
|
||||||
|
return Err(S3Error::with_message(
|
||||||
|
S3ErrorCode::ReplicationConfigurationNotFoundError,
|
||||||
|
"replication not found".to_string(),
|
||||||
|
));
|
||||||
|
}
|
||||||
error!("get_replication_config err {:?}", err);
|
error!("get_replication_config err {:?}", err);
|
||||||
return Err(ApiError::from(err).into());
|
return Err(ApiError::from(err).into());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if rcfg.is_none() {
|
if rcfg.is_none() {
|
||||||
return Err(S3Error::with_message(S3ErrorCode::NoSuchBucket, "replication not found".to_string()));
|
return Err(S3Error::with_message(
|
||||||
|
S3ErrorCode::ReplicationConfigurationNotFoundError,
|
||||||
|
"replication not found".to_string(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ok(S3Response::new(GetBucketReplicationOutput {
|
// Ok(S3Response::new(GetBucketReplicationOutput {
|
||||||
|
|||||||
Reference in New Issue
Block a user