mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-25 13:36:50 +00:00
test(object): cover zero-copy selection heuristics (#2338)
Co-authored-by: houseme <housemecn@gmail.com> Co-authored-by: cxymds <Cxymds@qq.com>
This commit is contained in:
@@ -95,15 +95,16 @@ use rustfs_s3select_api::{
|
|||||||
use rustfs_s3select_query::get_global_db;
|
use rustfs_s3select_query::get_global_db;
|
||||||
use rustfs_targets::EventName;
|
use rustfs_targets::EventName;
|
||||||
use rustfs_utils::http::{
|
use rustfs_utils::http::{
|
||||||
AMZ_BUCKET_REPLICATION_STATUS, AMZ_CHECKSUM_MODE, AMZ_CHECKSUM_TYPE, AMZ_WEBSITE_REDIRECT_LOCATION, SUFFIX_ACTUAL_SIZE,
|
AMZ_BUCKET_REPLICATION_STATUS, AMZ_CHECKSUM_MODE, AMZ_CHECKSUM_TYPE, AMZ_WEBSITE_REDIRECT_LOCATION, CONTENT_TYPE,
|
||||||
SUFFIX_COMPRESSION, SUFFIX_COMPRESSION_SIZE, SUFFIX_REPLICATION_STATUS, SUFFIX_REPLICATION_TIMESTAMP,
|
SUFFIX_ACTUAL_SIZE, SUFFIX_COMPRESSION, SUFFIX_COMPRESSION_SIZE, SUFFIX_REPLICATION_STATUS, SUFFIX_REPLICATION_TIMESTAMP,
|
||||||
headers::{
|
headers::{
|
||||||
AMZ_DECODED_CONTENT_LENGTH, AMZ_MINIO_SNOWBALL_IGNORE_DIRS, AMZ_MINIO_SNOWBALL_IGNORE_ERRORS, AMZ_MINIO_SNOWBALL_PREFIX,
|
AMZ_DECODED_CONTENT_LENGTH, AMZ_MINIO_SNOWBALL_IGNORE_DIRS, AMZ_MINIO_SNOWBALL_IGNORE_ERRORS, AMZ_MINIO_SNOWBALL_PREFIX,
|
||||||
AMZ_OBJECT_LOCK_LEGAL_HOLD, AMZ_OBJECT_LOCK_LEGAL_HOLD_LOWER, AMZ_OBJECT_LOCK_MODE, AMZ_OBJECT_LOCK_MODE_LOWER,
|
AMZ_OBJECT_LOCK_LEGAL_HOLD, AMZ_OBJECT_LOCK_LEGAL_HOLD_LOWER, AMZ_OBJECT_LOCK_MODE, AMZ_OBJECT_LOCK_MODE_LOWER,
|
||||||
AMZ_OBJECT_LOCK_RETAIN_UNTIL_DATE, AMZ_OBJECT_LOCK_RETAIN_UNTIL_DATE_LOWER, AMZ_OBJECT_TAGGING, AMZ_RESTORE_EXPIRY_DAYS,
|
AMZ_OBJECT_LOCK_RETAIN_UNTIL_DATE, AMZ_OBJECT_LOCK_RETAIN_UNTIL_DATE_LOWER, AMZ_OBJECT_TAGGING, AMZ_RESTORE_EXPIRY_DAYS,
|
||||||
AMZ_RESTORE_REQUEST_DATE, AMZ_RUSTFS_SNOWBALL_IGNORE_DIRS, AMZ_RUSTFS_SNOWBALL_IGNORE_ERRORS, AMZ_RUSTFS_SNOWBALL_PREFIX,
|
AMZ_RESTORE_REQUEST_DATE, AMZ_RUSTFS_SNOWBALL_IGNORE_DIRS, AMZ_RUSTFS_SNOWBALL_IGNORE_ERRORS, AMZ_RUSTFS_SNOWBALL_PREFIX,
|
||||||
AMZ_SERVER_SIDE_ENCRYPTION, AMZ_SERVER_SIDE_ENCRYPTION_KMS_ID, AMZ_SNOWBALL_EXTRACT, AMZ_SNOWBALL_IGNORE_DIRS,
|
AMZ_SERVER_SIDE_ENCRYPTION, AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_ALGORITHM, AMZ_SERVER_SIDE_ENCRYPTION_KMS_ID,
|
||||||
AMZ_SNOWBALL_IGNORE_ERRORS, AMZ_SNOWBALL_PREFIX, AMZ_STORAGE_CLASS, AMZ_TAG_COUNT,
|
AMZ_SNOWBALL_EXTRACT, AMZ_SNOWBALL_IGNORE_DIRS, AMZ_SNOWBALL_IGNORE_ERRORS, AMZ_SNOWBALL_PREFIX, AMZ_STORAGE_CLASS,
|
||||||
|
AMZ_TAG_COUNT,
|
||||||
},
|
},
|
||||||
insert_str, remove_str,
|
insert_str, remove_str,
|
||||||
};
|
};
|
||||||
@@ -314,24 +315,24 @@ impl<R: AsyncRead> AsyncRead for ExtractArchiveEtagReader<R> {
|
|||||||
///
|
///
|
||||||
/// `true` if zero-copy should be used, `false` otherwise
|
/// `true` if zero-copy should be used, `false` otherwise
|
||||||
fn should_use_zero_copy(size: i64, headers: &HeaderMap) -> bool {
|
fn should_use_zero_copy(size: i64, headers: &HeaderMap) -> bool {
|
||||||
// Only use zero-copy for large objects (> 1MB)
|
// Only use zero-copy for objects larger than 1MB
|
||||||
const ZERO_COPY_MIN_SIZE: i64 = 1024 * 1024;
|
const ZERO_COPY_MIN_SIZE: i64 = 1024 * 1024;
|
||||||
|
|
||||||
if size < ZERO_COPY_MIN_SIZE {
|
if size <= ZERO_COPY_MIN_SIZE {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't use zero-copy if encryption is requested
|
// Don't use zero-copy if encryption is requested
|
||||||
if headers.get("x-amz-server-side-encryption").is_some()
|
if headers.get(AMZ_SERVER_SIDE_ENCRYPTION).is_some()
|
||||||
|| headers.get("x-amz-server-side-encryption-customer-algorithm").is_some()
|
|| headers.get(AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_ALGORITHM).is_some()
|
||||||
|| headers.get("x-amz-server-side-encryption-aws-kms-key-id").is_some()
|
|| headers.get(AMZ_SERVER_SIDE_ENCRYPTION_KMS_ID).is_some()
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't use zero-copy if compression is likely (compressible content types)
|
// Don't use zero-copy if compression is likely (compressible content types)
|
||||||
// The compression check happens later in the flow
|
// The compression check happens later in the flow
|
||||||
if let Some(content_type) = headers.get("content-type")
|
if let Some(content_type) = headers.get(CONTENT_TYPE)
|
||||||
&& let Ok(ct) = content_type.to_str()
|
&& let Ok(ct) = content_type.to_str()
|
||||||
{
|
{
|
||||||
// Skip zero-copy for easily compressible content types
|
// Skip zero-copy for easily compressible content types
|
||||||
@@ -5166,6 +5167,67 @@ mod tests {
|
|||||||
assert_eq!(normalize_extract_entry_key("top-level", None, false), "top-level");
|
assert_eq!(normalize_extract_entry_key("top-level", None, false), "top-level");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_use_zero_copy_rejects_boundary_at_1mb() {
|
||||||
|
let headers = HeaderMap::new();
|
||||||
|
|
||||||
|
assert!(!should_use_zero_copy(1024 * 1024, &headers));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_use_zero_copy_rejects_small_objects() {
|
||||||
|
let headers = HeaderMap::new();
|
||||||
|
|
||||||
|
assert!(!should_use_zero_copy(1024 * 1024 - 1, &headers));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_use_zero_copy_rejects_one_megabyte() {
|
||||||
|
let headers = HeaderMap::new();
|
||||||
|
|
||||||
|
assert!(!should_use_zero_copy(1024 * 1024, &headers));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_use_zero_copy_rejects_encrypted_requests() {
|
||||||
|
let mut headers = HeaderMap::new();
|
||||||
|
headers.insert(AMZ_SERVER_SIDE_ENCRYPTION, HeaderValue::from_static("AES256"));
|
||||||
|
|
||||||
|
assert!(!should_use_zero_copy(2 * 1024 * 1024, &headers));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_use_zero_copy_rejects_encrypted_requests_with_sse_customer_algorithm() {
|
||||||
|
let mut headers = HeaderMap::new();
|
||||||
|
headers.insert(AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_ALGORITHM, HeaderValue::from_static("AES256"));
|
||||||
|
|
||||||
|
assert!(!should_use_zero_copy(2 * 1024 * 1024, &headers));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_use_zero_copy_rejects_encrypted_requests_with_kms_key_id() {
|
||||||
|
let mut headers = HeaderMap::new();
|
||||||
|
headers.insert(AMZ_SERVER_SIDE_ENCRYPTION_KMS_ID, HeaderValue::from_static("test-kms-key-id"));
|
||||||
|
|
||||||
|
assert!(!should_use_zero_copy(2 * 1024 * 1024, &headers));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_use_zero_copy_rejects_compressible_content_types() {
|
||||||
|
let mut headers = HeaderMap::new();
|
||||||
|
headers.insert(CONTENT_TYPE, HeaderValue::from_static("application/json; charset=utf-8"));
|
||||||
|
|
||||||
|
assert!(!should_use_zero_copy(2 * 1024 * 1024, &headers));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_use_zero_copy_allows_large_unencrypted_binary_objects() {
|
||||||
|
let mut headers = HeaderMap::new();
|
||||||
|
headers.insert(CONTENT_TYPE, HeaderValue::from_static("application/octet-stream"));
|
||||||
|
|
||||||
|
assert!(should_use_zero_copy(2 * 1024 * 1024, &headers));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn resolve_put_object_extract_options_defaults_when_headers_missing() {
|
fn resolve_put_object_extract_options_defaults_when_headers_missing() {
|
||||||
let headers = HeaderMap::new();
|
let headers = HeaderMap::new();
|
||||||
|
|||||||
Reference in New Issue
Block a user