mirror of
https://github.com/rustfs/rustfs.git
synced 2026-09-04 19:25:40 +00:00
refactor(app): inline object request context types (#2462)
This commit is contained in:
@@ -18,11 +18,9 @@ mod get_object_flow;
|
|||||||
mod get_object_zero_copy;
|
mod get_object_zero_copy;
|
||||||
mod put_object_extract;
|
mod put_object_extract;
|
||||||
mod put_object_flow;
|
mod put_object_flow;
|
||||||
mod types;
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod zero_copy_tests;
|
mod zero_copy_tests;
|
||||||
use self::get_object_flow::GetObjectBootstrap;
|
use self::get_object_flow::GetObjectBootstrap;
|
||||||
use self::types::*;
|
|
||||||
|
|
||||||
use crate::app::context::{AppContext, default_notify_interface, get_global_app_context};
|
use crate::app::context::{AppContext, default_notify_interface, get_global_app_context};
|
||||||
use crate::capacity::record_capacity_write;
|
use crate::capacity::record_capacity_write;
|
||||||
@@ -141,6 +139,34 @@ struct DeadlockRequestGuard {
|
|||||||
request_id: String,
|
request_id: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub(super) struct GetObjectRequestContext {
|
||||||
|
pub(super) bucket: String,
|
||||||
|
pub(super) key: String,
|
||||||
|
pub(super) part_number: Option<usize>,
|
||||||
|
pub(super) rs: Option<HTTPRangeSpec>,
|
||||||
|
pub(super) opts: ObjectOptions,
|
||||||
|
pub(super) headers: HeaderMap,
|
||||||
|
pub(super) sse_customer_key: Option<String>,
|
||||||
|
pub(super) sse_customer_key_md5: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) type PutObjectChecksums = rustfs_object_io::put::PutObjectChecksums;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub(super) struct PutObjectRequestContext {
|
||||||
|
pub(super) headers: HeaderMap,
|
||||||
|
pub(super) trailing_headers: Option<s3s::TrailingHeaders>,
|
||||||
|
pub(super) uri_query: Option<String>,
|
||||||
|
pub(super) is_post_object: bool,
|
||||||
|
pub(super) method: hyper::Method,
|
||||||
|
pub(super) uri: hyper::Uri,
|
||||||
|
pub(super) extensions: http::Extensions,
|
||||||
|
pub(super) credentials: Option<s3s::auth::Credentials>,
|
||||||
|
pub(super) region: Option<s3s::region::Region>,
|
||||||
|
pub(super) service: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
impl DeadlockRequestGuard {
|
impl DeadlockRequestGuard {
|
||||||
fn new(deadlock_detector: Arc<deadlock_detector::DeadlockDetector>, request_id: String) -> Self {
|
fn new(deadlock_detector: Arc<deadlock_detector::DeadlockDetector>, request_id: String) -> Self {
|
||||||
Self {
|
Self {
|
||||||
@@ -315,6 +341,58 @@ fn build_put_object_expiration_header(event: &lifecycle::Event) -> Option<String
|
|||||||
Some(format!("expiry-date=\"{}\", rule-id=\"{}\"", expiry_date, event.rule_id))
|
Some(format!("expiry-date=\"{}\", rule-id=\"{}\"", expiry_date, event.rule_id))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn prepare_get_object_request_context(req: &S3Request<GetObjectInput>) -> S3Result<GetObjectRequestContext> {
|
||||||
|
let GetObjectInput {
|
||||||
|
bucket,
|
||||||
|
key,
|
||||||
|
version_id,
|
||||||
|
part_number,
|
||||||
|
range,
|
||||||
|
..
|
||||||
|
} = req.input.clone();
|
||||||
|
|
||||||
|
validate_object_key(&key, "GET")?;
|
||||||
|
|
||||||
|
let part_number = part_number.map(|value| value as usize);
|
||||||
|
if let Some(part_number) = part_number
|
||||||
|
&& part_number == 0
|
||||||
|
{
|
||||||
|
return Err(s3_error!(InvalidArgument, "Invalid part number: part number must be greater than 0"));
|
||||||
|
}
|
||||||
|
|
||||||
|
let rs = range.map(|value| match value {
|
||||||
|
Range::Int { first, last } => HTTPRangeSpec {
|
||||||
|
is_suffix_length: false,
|
||||||
|
start: first as i64,
|
||||||
|
end: last.map_or(-1, |last| last as i64),
|
||||||
|
},
|
||||||
|
Range::Suffix { length } => HTTPRangeSpec {
|
||||||
|
is_suffix_length: true,
|
||||||
|
start: length as i64,
|
||||||
|
end: -1,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if rs.is_some() && part_number.is_some() {
|
||||||
|
return Err(s3_error!(InvalidArgument, "range and part_number invalid"));
|
||||||
|
}
|
||||||
|
|
||||||
|
let opts: ObjectOptions = get_opts(&bucket, &key, version_id, part_number, &req.headers)
|
||||||
|
.await
|
||||||
|
.map_err(ApiError::from)?;
|
||||||
|
|
||||||
|
Ok(GetObjectRequestContext {
|
||||||
|
bucket,
|
||||||
|
key,
|
||||||
|
part_number,
|
||||||
|
rs,
|
||||||
|
opts,
|
||||||
|
headers: req.headers.clone(),
|
||||||
|
sse_customer_key: req.input.sse_customer_key.clone(),
|
||||||
|
sse_customer_key_md5: req.input.sse_customer_key_md5.clone(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn apply_put_request_metadata(
|
fn apply_put_request_metadata(
|
||||||
metadata: &mut HashMap<String, String>,
|
metadata: &mut HashMap<String, String>,
|
||||||
@@ -1065,60 +1143,8 @@ impl DefaultObjectUsecase {
|
|||||||
_deadlock_request_guard: deadlock_request_guard,
|
_deadlock_request_guard: deadlock_request_guard,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let (request_context, version_id_for_event) = {
|
let version_id_for_event = req.input.version_id.clone().unwrap_or_default();
|
||||||
let GetObjectInput {
|
let request_context = prepare_get_object_request_context(&req).await?;
|
||||||
bucket,
|
|
||||||
key,
|
|
||||||
version_id,
|
|
||||||
part_number,
|
|
||||||
range,
|
|
||||||
..
|
|
||||||
} = req.input.clone();
|
|
||||||
|
|
||||||
validate_object_key(&key, "GET")?;
|
|
||||||
|
|
||||||
let part_number = part_number.map(|value| value as usize);
|
|
||||||
if let Some(part_number) = part_number
|
|
||||||
&& part_number == 0
|
|
||||||
{
|
|
||||||
return Err(s3_error!(InvalidArgument, "Invalid part number: part number must be greater than 0"));
|
|
||||||
}
|
|
||||||
|
|
||||||
let rs = range.map(|value| match value {
|
|
||||||
Range::Int { first, last } => HTTPRangeSpec {
|
|
||||||
is_suffix_length: false,
|
|
||||||
start: first as i64,
|
|
||||||
end: last.map_or(-1, |last| last as i64),
|
|
||||||
},
|
|
||||||
Range::Suffix { length } => HTTPRangeSpec {
|
|
||||||
is_suffix_length: true,
|
|
||||||
start: length as i64,
|
|
||||||
end: -1,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if rs.is_some() && part_number.is_some() {
|
|
||||||
return Err(s3_error!(InvalidArgument, "range and part_number invalid"));
|
|
||||||
}
|
|
||||||
|
|
||||||
let opts: ObjectOptions = get_opts(&bucket, &key, version_id.clone(), part_number, &req.headers)
|
|
||||||
.await
|
|
||||||
.map_err(ApiError::from)?;
|
|
||||||
|
|
||||||
(
|
|
||||||
GetObjectRequestContext {
|
|
||||||
bucket,
|
|
||||||
key,
|
|
||||||
part_number,
|
|
||||||
rs,
|
|
||||||
opts,
|
|
||||||
headers: req.headers.clone(),
|
|
||||||
sse_customer_key: req.input.sse_customer_key.clone(),
|
|
||||||
sse_customer_key_md5: req.input.sse_customer_key_md5.clone(),
|
|
||||||
},
|
|
||||||
version_id.unwrap_or_default(),
|
|
||||||
)
|
|
||||||
};
|
|
||||||
let base_buffer_size = self.base_buffer_size();
|
let base_buffer_size = self.base_buffer_size();
|
||||||
let manager = get_concurrency_manager();
|
let manager = get_concurrency_manager();
|
||||||
let cors_bucket = request_context.bucket.clone();
|
let cors_bucket = request_context.bucket.clone();
|
||||||
|
|||||||
@@ -13,8 +13,8 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use super::DeadlockRequestGuard;
|
use super::DeadlockRequestGuard;
|
||||||
|
use super::GetObjectRequestContext;
|
||||||
use super::get_object_zero_copy::{GetObjectIoPlanning, GetObjectPreparedRead, prepare_get_object_read_execution};
|
use super::get_object_zero_copy::{GetObjectIoPlanning, GetObjectPreparedRead, prepare_get_object_read_execution};
|
||||||
use super::types::GetObjectRequestContext;
|
|
||||||
use crate::error::ApiError;
|
use crate::error::ApiError;
|
||||||
use crate::storage::concurrency::{ConcurrencyManager, GetObjectGuard, get_buffer_size_opt_in};
|
use crate::storage::concurrency::{ConcurrencyManager, GetObjectGuard, get_buffer_size_opt_in};
|
||||||
use crate::storage::options::filter_object_metadata;
|
use crate::storage::options::filter_object_metadata;
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use super::types::GetObjectRequestContext;
|
use super::GetObjectRequestContext;
|
||||||
use crate::error::ApiError;
|
use crate::error::ApiError;
|
||||||
use crate::storage::concurrency::{self, ConcurrencyManager};
|
use crate::storage::concurrency::{self, ConcurrencyManager};
|
||||||
use crate::storage::timeout_wrapper::{RequestTimeoutWrapper, TimeoutConfig};
|
use crate::storage::timeout_wrapper::{RequestTimeoutWrapper, TimeoutConfig};
|
||||||
|
|||||||
@@ -1,43 +0,0 @@
|
|||||||
// Copyright 2024 RustFS Team
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub(super) struct GetObjectRequestContext {
|
|
||||||
pub(super) bucket: String,
|
|
||||||
pub(super) key: String,
|
|
||||||
pub(super) part_number: Option<usize>,
|
|
||||||
pub(super) rs: Option<HTTPRangeSpec>,
|
|
||||||
pub(super) opts: ObjectOptions,
|
|
||||||
pub(super) headers: HeaderMap,
|
|
||||||
pub(super) sse_customer_key: Option<String>,
|
|
||||||
pub(super) sse_customer_key_md5: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) type PutObjectChecksums = rustfs_object_io::put::PutObjectChecksums;
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub(super) struct PutObjectRequestContext {
|
|
||||||
pub(super) headers: HeaderMap,
|
|
||||||
pub(super) trailing_headers: Option<s3s::TrailingHeaders>,
|
|
||||||
pub(super) uri_query: Option<String>,
|
|
||||||
pub(super) is_post_object: bool,
|
|
||||||
pub(super) method: hyper::Method,
|
|
||||||
pub(super) uri: hyper::Uri,
|
|
||||||
pub(super) extensions: http::Extensions,
|
|
||||||
pub(super) credentials: Option<s3s::auth::Credentials>,
|
|
||||||
pub(super) region: Option<s3s::region::Region>,
|
|
||||||
pub(super) service: Option<String>,
|
|
||||||
}
|
|
||||||
@@ -40,58 +40,6 @@ static DIRECT_CHUNK_TEST_ENV: OnceLock<(Vec<PathBuf>, Arc<ECStore>)> = OnceLock:
|
|||||||
static DIRECT_CHUNK_MULTI_DISK_TEST_ENV: OnceLock<(Vec<PathBuf>, Arc<ECStore>)> = OnceLock::new();
|
static DIRECT_CHUNK_MULTI_DISK_TEST_ENV: OnceLock<(Vec<PathBuf>, Arc<ECStore>)> = OnceLock::new();
|
||||||
static DIRECT_CHUNK_TEST_INIT: Once = Once::new();
|
static DIRECT_CHUNK_TEST_INIT: Once = Once::new();
|
||||||
|
|
||||||
async fn prepare_get_object_request_context(req: &S3Request<GetObjectInput>) -> S3Result<GetObjectRequestContext> {
|
|
||||||
let GetObjectInput {
|
|
||||||
bucket,
|
|
||||||
key,
|
|
||||||
version_id,
|
|
||||||
part_number,
|
|
||||||
range,
|
|
||||||
..
|
|
||||||
} = req.input.clone();
|
|
||||||
|
|
||||||
validate_object_key(&key, "GET")?;
|
|
||||||
|
|
||||||
let part_number = part_number.map(|value| value as usize);
|
|
||||||
if let Some(part_number) = part_number
|
|
||||||
&& part_number == 0
|
|
||||||
{
|
|
||||||
return Err(s3_error!(InvalidArgument, "Invalid part number: part number must be greater than 0"));
|
|
||||||
}
|
|
||||||
|
|
||||||
let rs = range.map(|value| match value {
|
|
||||||
Range::Int { first, last } => HTTPRangeSpec {
|
|
||||||
is_suffix_length: false,
|
|
||||||
start: first as i64,
|
|
||||||
end: last.map_or(-1, |last| last as i64),
|
|
||||||
},
|
|
||||||
Range::Suffix { length } => HTTPRangeSpec {
|
|
||||||
is_suffix_length: true,
|
|
||||||
start: length as i64,
|
|
||||||
end: -1,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if rs.is_some() && part_number.is_some() {
|
|
||||||
return Err(s3_error!(InvalidArgument, "range and part_number invalid"));
|
|
||||||
}
|
|
||||||
|
|
||||||
let opts: ObjectOptions = get_opts(&bucket, &key, version_id.clone(), part_number, &req.headers)
|
|
||||||
.await
|
|
||||||
.map_err(ApiError::from)?;
|
|
||||||
|
|
||||||
Ok(GetObjectRequestContext {
|
|
||||||
bucket,
|
|
||||||
key,
|
|
||||||
part_number,
|
|
||||||
rs,
|
|
||||||
opts,
|
|
||||||
headers: req.headers.clone(),
|
|
||||||
sse_customer_key: req.input.sse_customer_key.clone(),
|
|
||||||
sse_customer_key_md5: req.input.sse_customer_key_md5.clone(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn init_direct_chunk_test_tracing() {
|
fn init_direct_chunk_test_tracing() {
|
||||||
DIRECT_CHUNK_TEST_INIT.call_once(|| {});
|
DIRECT_CHUNK_TEST_INIT.call_once(|| {});
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user