revert: remove #2351 chunk I/O and object-io crate (phase 7) (#2543)

Co-authored-by: houseme <housemecn@gmail.com>
This commit is contained in:
安正超
2026-04-15 10:54:41 +08:00
committed by GitHub
parent 16b9189e9b
commit 642d83f0e4
22 changed files with 2757 additions and 3815 deletions
+12 -39
View File
@@ -150,7 +150,18 @@ impl Config {
return false;
}
shard_size as usize <= self.inline_shard_limit_bytes(versioned)
let shard_size = shard_size as usize;
let mut inline_block = DEFAULT_INLINE_BLOCK;
if self.initialized {
inline_block = self.inline_block;
}
if versioned {
shard_size <= inline_block / 8
} else {
shard_size <= inline_block
}
}
pub fn inline_block(&self) -> usize {
@@ -161,15 +172,6 @@ impl Config {
}
}
pub fn inline_shard_limit_bytes(&self, versioned: bool) -> usize {
let inline_block = self.inline_block();
if versioned { inline_block / 8 } else { inline_block }
}
pub fn inline_object_limit_bytes(&self, data_shards: usize, versioned: bool) -> usize {
self.inline_shard_limit_bytes(versioned).saturating_mul(data_shards.max(1))
}
pub fn capacity_optimized(&self) -> bool {
if !self.initialized {
false
@@ -334,32 +336,3 @@ pub fn validate_parity_inner(ss_parity: usize, rrs_parity: usize, set_drive_coun
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn inline_object_limit_matches_default_non_versioned_budget() {
let cfg = Config {
initialized: true,
inline_block: DEFAULT_INLINE_BLOCK,
..Default::default()
};
assert_eq!(cfg.inline_shard_limit_bytes(false), DEFAULT_INLINE_BLOCK);
assert_eq!(cfg.inline_object_limit_bytes(8, false), DEFAULT_INLINE_BLOCK * 8);
}
#[test]
fn inline_object_limit_scales_down_for_versioned_objects() {
let cfg = Config {
initialized: true,
inline_block: DEFAULT_INLINE_BLOCK,
..Default::default()
};
assert_eq!(cfg.inline_shard_limit_bytes(true), DEFAULT_INLINE_BLOCK / 8);
assert_eq!(cfg.inline_object_limit_bytes(8, true), DEFAULT_INLINE_BLOCK);
}
}
+4 -4
View File
@@ -64,7 +64,7 @@ pub fn decode_part_index(index: Option<&Bytes>) -> Option<Index> {
}
}
pub fn put_data_from_chunk(chunk: Vec<u8>, size: i64, actual_size: i64, index: Option<Index>) -> Result<PutObjReader> {
pub fn put_obj_reader_from_chunk(chunk: Vec<u8>, size: i64, actual_size: i64, index: Option<Index>) -> Result<PutObjReader> {
use sha2::{Digest, Sha256};
let sha256hex = if !chunk.is_empty() {
@@ -74,7 +74,7 @@ pub fn put_data_from_chunk(chunk: Vec<u8>, size: i64, actual_size: i64, index: O
};
let reader = IndexedDataMovementReader::new(Cursor::new(chunk), index);
let hash_reader = HashReader::from_reader(reader, size, actual_size, None, sha256hex, false)?;
let hash_reader = HashReader::from_stream(reader, size, actual_size, None, sha256hex, false)?;
Ok(PutObjReader::new(hash_reader))
}
@@ -172,7 +172,7 @@ pub(crate) async fn migrate_object(
let part_size = i64::try_from(part.size).map_err(|_| Error::other("part size overflow"))?;
let part_actual_size = if part.actual_size > 0 { part.actual_size } else { part_size };
let index = decode_part_index(part.index.as_ref());
let mut data = put_data_from_chunk(chunk, part_size, part_actual_size, index)?;
let mut data = put_obj_reader_from_chunk(chunk, part_size, part_actual_size, index)?;
let pi = match store
.put_object_part(
@@ -254,7 +254,7 @@ pub(crate) async fn migrate_object(
.first()
.and_then(|part| decode_part_index(part.index.as_ref()));
let reader = IndexedDataMovementReader::new(BufReader::new(rd.stream), index);
let hrd = HashReader::from_reader(reader, object_info.size, actual_size, object_info.etag.clone(), None, false)?;
let hrd = HashReader::from_stream(reader, object_info.size, actual_size, object_info.etag.clone(), None, false)?;
let mut data = PutObjReader::new(hrd);
if let Err(err) = store
+16 -167
View File
@@ -119,19 +119,18 @@ use tokio::{
time::{interval, timeout},
};
use tokio_util::sync::CancellationToken;
use tracing::error;
use tracing::{debug, info, warn};
use uuid::Uuid;
const ENV_RUSTFS_PUT_INLINE_OBJECT_MAX_BYTES: &str = "RUSTFS_PUT_INLINE_OBJECT_MAX_BYTES";
const ENV_RUSTFS_PUT_FORCE_DISABLE_INLINE: &str = "RUSTFS_PUT_FORCE_DISABLE_INLINE";
const SLOW_PUT_STORAGE_PHASE_DEBUG_THRESHOLD_MS: u64 = 100;
const SLOW_PUT_STORAGE_PHASE_WARN_THRESHOLD_MS: u64 = 1_000;
const SLOW_PUT_STORAGE_PHASE_ERROR_THRESHOLD_MS: u64 = 5_000;
pub const DEFAULT_READ_BUFFER_SIZE: usize = MI_B; // 1 MiB = 1024 * 1024;
pub const MAX_PARTS_COUNT: usize = 10000;
pub(crate) const RUSTFS_MULTIPART_BUCKET_KEY: &str = "x-rustfs-internal-multipart-bucket";
pub(crate) const RUSTFS_MULTIPART_OBJECT_KEY: &str = "x-rustfs-internal-multipart-object";
fn env_flag_enabled(name: &str) -> bool {
rustfs_utils::get_env_bool(name, false)
}
fn env_non_negative_usize(name: &str) -> Option<usize> {
rustfs_utils::get_env_opt_usize(name)
pub(crate) fn strip_internal_multipart_metadata(metadata: &mut HashMap<String, String>) {
metadata.remove(RUSTFS_MULTIPART_BUCKET_KEY);
metadata.remove(RUSTFS_MULTIPART_OBJECT_KEY);
}
fn capacity_scope_from_disks(disks: &[Option<DiskStore>]) -> CapacityScope {
@@ -164,65 +163,6 @@ fn record_capacity_scope_if_needed(scope_token: Option<Uuid>, disks: &[Option<Di
}
}
fn resolved_put_inline_buffer_enabled(object_size: i64, inline_by_topology: bool) -> bool {
if !inline_by_topology || object_size < 0 {
return false;
}
if env_flag_enabled(ENV_RUSTFS_PUT_FORCE_DISABLE_INLINE) {
return false;
}
env_non_negative_usize(ENV_RUSTFS_PUT_INLINE_OBJECT_MAX_BYTES)
.map(|value| usize::try_from(object_size).is_ok_and(|size| size <= value))
.unwrap_or(inline_by_topology)
}
fn log_put_storage_phase(
bucket: &str,
object: &str,
phase: &str,
elapsed: Duration,
object_size: i64,
inline_selected: bool,
write_quorum: usize,
) {
let duration_ms = elapsed.as_millis() as u64;
if duration_ms < SLOW_PUT_STORAGE_PHASE_DEBUG_THRESHOLD_MS {
return;
}
if duration_ms >= SLOW_PUT_STORAGE_PHASE_ERROR_THRESHOLD_MS {
error!(
phase,
duration_ms, object_size, inline_selected, write_quorum, bucket, object, "PUT storage phase is critically slow"
);
} else if duration_ms >= SLOW_PUT_STORAGE_PHASE_WARN_THRESHOLD_MS {
warn!(
phase,
duration_ms, object_size, inline_selected, write_quorum, bucket, object, "PUT storage phase is slow"
);
} else {
debug!(
phase,
duration_ms, object_size, inline_selected, write_quorum, bucket, object, "PUT storage phase exceeded debug threshold"
);
}
}
use tracing::error;
use tracing::{debug, info, warn};
use uuid::Uuid;
pub const DEFAULT_READ_BUFFER_SIZE: usize = MI_B; // 1 MiB = 1024 * 1024;
pub const MAX_PARTS_COUNT: usize = 10000;
pub(crate) const RUSTFS_MULTIPART_BUCKET_KEY: &str = "x-rustfs-internal-multipart-bucket";
pub(crate) const RUSTFS_MULTIPART_OBJECT_KEY: &str = "x-rustfs-internal-multipart-object";
pub(crate) fn strip_internal_multipart_metadata(metadata: &mut HashMap<String, String>) {
metadata.remove(RUSTFS_MULTIPART_BUCKET_KEY);
metadata.remove(RUSTFS_MULTIPART_OBJECT_KEY);
}
/// Get the duplex buffer size from environment variable or use default.
///
/// This function reads `RUSTFS_DUPLEX_BUFFER_SIZE` environment variable
@@ -872,18 +812,13 @@ impl ObjectIO for SetDisks {
let erasure = erasure_coding::Erasure::new(fi.erasure.data_blocks, fi.erasure.parity_blocks, fi.erasure.block_size);
let is_inline_buffer = {
let inline_by_topology = if let Some(sc) = GLOBAL_STORAGE_CLASS.get() {
if let Some(sc) = GLOBAL_STORAGE_CLASS.get() {
sc.should_inline(erasure.shard_file_size(data.size()), opts.versioned)
} else {
false
};
resolved_put_inline_buffer_enabled(data.size(), inline_by_topology)
}
};
if is_inline_buffer {
rustfs_io_metrics::record_put_inline_selected(data.size(), opts.versioned);
}
let writer_setup_start = Instant::now();
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() {
@@ -917,15 +852,6 @@ impl ObjectIO for SetDisks {
writers.push(None);
}
}
log_put_storage_phase(
bucket,
object,
"writer_setup",
writer_setup_start.elapsed(),
data.size(),
is_inline_buffer,
write_quorum,
);
let nil_count = errors.iter().filter(|&e| e.is_none()).count();
if nil_count < write_quorum {
@@ -937,9 +863,6 @@ impl ObjectIO for SetDisks {
return Err(Error::other(format!("not enough disks to write: {errors:?}")));
}
let object_size = data.size();
let encode_write_start = Instant::now();
let stream = mem::replace(
&mut data.stream,
HashReader::from_stream(Cursor::new(Vec::new()), 0, 0, None, None, false)?,
@@ -948,30 +871,15 @@ impl ObjectIO for SetDisks {
let (reader, w_size) = match Arc::new(erasure).encode(stream, &mut writers, write_quorum).await {
Ok((r, w)) => (r, w),
Err(e) => {
log_put_storage_phase(
bucket,
object,
"encode_write",
encode_write_start.elapsed(),
object_size,
is_inline_buffer,
write_quorum,
);
error!("encode err {:?}", e);
return Err(e.into());
}
}; // TODO: delete temporary directory on error
let _ = mem::replace(&mut data.stream, reader);
log_put_storage_phase(
bucket,
object,
"encode_write",
encode_write_start.elapsed(),
object_size,
is_inline_buffer,
write_quorum,
);
// if let Err(err) = close_bitrot_writers(&mut writers).await {
// error!("close_bitrot_writers err {:?}", err);
// }
if (w_size as i64) < data.size() {
warn!("put_object write size < data.size(), w_size={}, data.size={}", w_size, data.size());
@@ -1047,7 +955,6 @@ impl ObjectIO for SetDisks {
drop(writers); // drop writers to close all files, this is to prevent FileAccessDenied errors when renaming data
let post_write_lock_start = Instant::now();
if !opts.no_lock && object_lock_guard.is_none() {
let ns_lock = self.new_ns_lock(bucket, object).await?;
object_lock_guard = Some(ns_lock.get_write_lock(get_lock_acquire_timeout()).await.map_err(|e| {
@@ -1057,17 +964,7 @@ impl ObjectIO for SetDisks {
))
})?);
}
log_put_storage_phase(
bucket,
object,
"post_write_lock",
post_write_lock_start.elapsed(),
data.size(),
is_inline_buffer,
write_quorum,
);
let finalize_start = Instant::now();
let (online_disks, _, op_old_dir) = Self::rename_data(
&shuffle_disks,
RUSTFS_META_TMP_BUCKET,
@@ -1077,18 +974,7 @@ impl ObjectIO for SetDisks {
object,
write_quorum,
)
.await
.inspect_err(|_| {
log_put_storage_phase(
bucket,
object,
"finalize",
finalize_start.elapsed(),
data.size(),
is_inline_buffer,
write_quorum,
);
})?;
.await?;
if let Some(old_dir) = op_old_dir {
self.commit_rename_data_dir(&online_disks, bucket, object, &old_dir.to_string(), write_quorum)
@@ -1098,15 +984,6 @@ impl ObjectIO for SetDisks {
drop(object_lock_guard); // drop object lock guard to release the lock
self.delete_all(RUSTFS_META_TMP_BUCKET, &tmp_dir).await?;
log_put_storage_phase(
bucket,
object,
"finalize",
finalize_start.elapsed(),
data.size(),
is_inline_buffer,
write_quorum,
);
for (i, op_disk) in online_disks.iter().enumerate() {
if let Some(disk) = op_disk
@@ -2037,9 +1914,6 @@ impl ObjectOperations for SetDisks {
if let Some(ref version_id) = opts.version_id {
fi.version_id = Uuid::parse_str(version_id).ok();
}
if let Some(checksum) = &opts.resolved_checksum {
fi.checksum = Some(checksum.clone());
}
self.update_object_meta(bucket, object, fi.clone(), &online_disks)
.await
@@ -4403,31 +4277,6 @@ mod tests {
}
}
#[test]
#[serial]
fn resolved_put_inline_buffer_enabled_honors_disable_env() {
temp_env::with_var(ENV_RUSTFS_PUT_FORCE_DISABLE_INLINE, Some("true"), || {
assert!(!resolved_put_inline_buffer_enabled(4096, true));
});
}
#[test]
#[serial]
fn resolved_put_inline_buffer_enabled_honors_max_bytes_override() {
temp_env::with_var(ENV_RUSTFS_PUT_INLINE_OBJECT_MAX_BYTES, Some("4096"), || {
assert!(resolved_put_inline_buffer_enabled(4096, true));
assert!(!resolved_put_inline_buffer_enabled(4097, true));
});
}
#[test]
#[serial]
fn resolved_put_inline_buffer_enabled_ignores_invalid_override() {
temp_env::with_var(ENV_RUSTFS_PUT_INLINE_OBJECT_MAX_BYTES, Some("invalid"), || {
assert!(resolved_put_inline_buffer_enabled(4096, true));
});
}
async fn current_setup_type() -> SetupType {
if is_dist_erasure().await {
SetupType::DistErasure
-14
View File
@@ -70,7 +70,6 @@ pub struct ObjectOptions {
pub eval_metadata: Option<HashMap<String, String>>,
pub resolved_checksum: Option<Bytes>,
pub want_checksum: Option<Checksum>,
pub skip_verify_bitrot: bool,
pub capacity_scope_token: Option<Uuid>,
@@ -511,18 +510,6 @@ impl ObjectInfo {
})
.collect();
let actual_size = fi
.parts
.iter()
.map(|part| {
if part.actual_size > 0 {
part.actual_size
} else {
i64::try_from(part.size).unwrap_or_default()
}
})
.sum();
// TODO: part checksums
ObjectInfo {
@@ -535,7 +522,6 @@ impl ObjectInfo {
delete_marker: fi.deleted,
mod_time: fi.mod_time,
size: fi.size,
actual_size,
parts,
is_latest: fi.is_latest,
user_tags,