mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-09 22:59:59 +00:00
fix(data-usage): refresh admin usage after object changes (#3081)
Co-authored-by: Henry Guo <marshawcoco@users.noreply.github.com>
This commit is contained in:
@@ -19,7 +19,7 @@ use crate::capacity::resolve_admin_used_capacity;
|
||||
use crate::error::ApiError;
|
||||
use rustfs_data_usage::DataUsageInfo;
|
||||
use rustfs_ecstore::admin_server_info::get_server_info;
|
||||
use rustfs_ecstore::data_usage::load_data_usage_from_backend;
|
||||
use rustfs_ecstore::data_usage::{apply_bucket_usage_memory_overlay, load_data_usage_from_backend};
|
||||
use rustfs_ecstore::endpoints::EndpointServerPools;
|
||||
use rustfs_ecstore::new_object_layer_fn;
|
||||
use rustfs_ecstore::pools::{PoolDecommissionInfo, PoolStatus, get_total_usable_capacity, get_total_usable_capacity_free};
|
||||
@@ -154,6 +154,7 @@ impl DefaultAdminUsecase {
|
||||
error!("load_data_usage_from_backend failed {:?}", e);
|
||||
Self::app_error(S3ErrorCode::InternalError, "load_data_usage_from_backend failed")
|
||||
})?;
|
||||
apply_bucket_usage_memory_overlay(&mut info).await;
|
||||
|
||||
let storage_info = store.storage_info().await;
|
||||
|
||||
|
||||
@@ -339,14 +339,18 @@ impl DefaultMultipartUsecase {
|
||||
let current_opts = get_opts(&bucket, &key, None, None, &req.headers)
|
||||
.await
|
||||
.map_err(ApiError::from)?;
|
||||
match store.get_object_info(&bucket, &key, ¤t_opts).await {
|
||||
Ok(existing_obj_info) => validate_existing_object_lock_for_write(&existing_obj_info)?,
|
||||
let previous_current_size = match store.get_object_info(&bucket, &key, ¤t_opts).await {
|
||||
Ok(existing_obj_info) => {
|
||||
validate_existing_object_lock_for_write(&existing_obj_info)?;
|
||||
Some(existing_obj_info.size.max(0) as u64)
|
||||
}
|
||||
Err(err) => {
|
||||
if !is_err_object_not_found(&err) && !is_err_version_not_found(&err) {
|
||||
return Err(ApiError::from(err).into());
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let multipart_info = store
|
||||
.get_multipart_info(&bucket, &key, &upload_id, &ObjectOptions::default())
|
||||
@@ -395,7 +399,12 @@ impl DefaultMultipartUsecase {
|
||||
));
|
||||
}
|
||||
// Update quota tracking after successful multipart upload
|
||||
rustfs_ecstore::data_usage::increment_bucket_usage_memory(&bucket, obj_info.size as u64).await;
|
||||
rustfs_ecstore::data_usage::record_bucket_object_write_memory(
|
||||
&bucket,
|
||||
previous_current_size,
|
||||
obj_info.size.max(0) as u64,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
Err(e) => {
|
||||
warn!("Quota check failed for bucket {}: {}, allowing operation", bucket, e);
|
||||
|
||||
@@ -1791,14 +1791,18 @@ impl DefaultObjectUsecase {
|
||||
let current_opts: ObjectOptions = get_opts(&bucket, &key, version_id.clone(), None, &req.headers)
|
||||
.await
|
||||
.map_err(ApiError::from)?;
|
||||
match store.get_object_info(&bucket, &key, ¤t_opts).await {
|
||||
Ok(existing_obj_info) => validate_existing_object_lock_for_write(&existing_obj_info)?,
|
||||
let previous_current_size = match store.get_object_info(&bucket, &key, ¤t_opts).await {
|
||||
Ok(existing_obj_info) => {
|
||||
validate_existing_object_lock_for_write(&existing_obj_info)?;
|
||||
Some(existing_obj_info.size.max(0) as u64)
|
||||
}
|
||||
Err(err) => {
|
||||
if !is_err_object_not_found(&err) && !is_err_version_not_found(&err) {
|
||||
return Err(ApiError::from(err).into());
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let actual_size = size;
|
||||
|
||||
@@ -1913,8 +1917,13 @@ impl DefaultObjectUsecase {
|
||||
|
||||
maybe_enqueue_transition_immediate(&obj_info, LcEventSrc::S3PutObject).await;
|
||||
|
||||
// Fast in-memory update for immediate quota consistency
|
||||
rustfs_ecstore::data_usage::increment_bucket_usage_memory(&bucket, obj_info.size as u64).await;
|
||||
// Fast in-memory update for immediate quota and admin usage consistency
|
||||
rustfs_ecstore::data_usage::record_bucket_object_write_memory(
|
||||
&bucket,
|
||||
previous_current_size,
|
||||
obj_info.size.max(0) as u64,
|
||||
)
|
||||
.await;
|
||||
|
||||
let raw_version = obj_info.version_id.map(|v| v.to_string());
|
||||
|
||||
@@ -2655,14 +2664,18 @@ impl DefaultObjectUsecase {
|
||||
let current_opts: ObjectOptions = get_opts(&bucket, &key, dest_version_id.clone(), None, &req.headers)
|
||||
.await
|
||||
.map_err(ApiError::from)?;
|
||||
match store.get_object_info(&bucket, &key, ¤t_opts).await {
|
||||
Ok(existing_obj_info) => validate_existing_object_lock_for_write(&existing_obj_info)?,
|
||||
let previous_current_size = match store.get_object_info(&bucket, &key, ¤t_opts).await {
|
||||
Ok(existing_obj_info) => {
|
||||
validate_existing_object_lock_for_write(&existing_obj_info)?;
|
||||
Some(existing_obj_info.size.max(0) as u64)
|
||||
}
|
||||
Err(err) => {
|
||||
if !is_err_object_not_found(&err) && !is_err_version_not_found(&err) {
|
||||
return Err(ApiError::from(err).into());
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let bucket_sse_config = metadata_sys::get_sse_config(&bucket).await.ok();
|
||||
let mut effective_sse = requested_sse.or_else(|| {
|
||||
@@ -2835,7 +2848,8 @@ impl DefaultObjectUsecase {
|
||||
|
||||
// Update quota tracking after successful copy
|
||||
if has_bucket_metadata {
|
||||
rustfs_ecstore::data_usage::increment_bucket_usage_memory(&bucket, oi.size as u64).await;
|
||||
rustfs_ecstore::data_usage::record_bucket_object_write_memory(&bucket, previous_current_size, oi.size.max(0) as u64)
|
||||
.await;
|
||||
}
|
||||
|
||||
let raw_dest_version = oi.version_id.map(|v| v.to_string());
|
||||
@@ -3091,10 +3105,13 @@ impl DefaultObjectUsecase {
|
||||
existing_object_infos[i].as_ref(),
|
||||
)
|
||||
.await;
|
||||
let size = object_sizes[i];
|
||||
if size > 0 {
|
||||
rustfs_ecstore::data_usage::decrement_bucket_usage_memory(&bucket, size as u64).await;
|
||||
}
|
||||
let size = object_sizes[i].max(0) as u64;
|
||||
rustfs_ecstore::data_usage::record_bucket_object_delete_memory(
|
||||
&bucket,
|
||||
size,
|
||||
existing_object_infos[i].is_some() && object_to_delete[i].version_id.is_none(),
|
||||
)
|
||||
.await;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -3309,8 +3326,13 @@ impl DefaultObjectUsecase {
|
||||
|
||||
enqueue_transitioned_delete_cleanup(&bucket, &key, &opts, existing_object_info.as_ref()).await;
|
||||
|
||||
// Fast in-memory update for immediate quota consistency
|
||||
rustfs_ecstore::data_usage::decrement_bucket_usage_memory(&bucket, obj_info.size as u64).await;
|
||||
// Fast in-memory update for immediate quota and admin usage consistency
|
||||
rustfs_ecstore::data_usage::record_bucket_object_delete_memory(
|
||||
&bucket,
|
||||
obj_info.size.max(0) as u64,
|
||||
opts.version_id.is_none(),
|
||||
)
|
||||
.await;
|
||||
|
||||
if obj_info.name.is_empty() {
|
||||
if replicate_force_delete {
|
||||
|
||||
Reference in New Issue
Block a user