perf(ecstore): improve erasure write diagnostics and single-block performance (#3280)
* docs(object-capacity): add localized crate docs * fix(ecstore): improve quorum and transport diagnostics * perf(ecstore): add safe single-block write fast path * refactor(ecstore): collapse layered small write paths * chore(docs): keep issue 662 design note tracked * fix(docs): restore issue 662 design note * chore(docs): keep issue 662 design local only * feat(obs): add internode reliability metrics and dashboard * feat(obs): extend internode diagnostics and service logging * fix(docs): use AGENTS guide filename * perf(ecstore): reuse owned buffer in small encode * fix(ecstore): tighten small write diagnostics --------- Co-authored-by: cxymds <[email protected]>
This commit is contained in:
@@ -280,18 +280,30 @@ async fn handle_put_file(req: Request<Incoming>) -> Response<Body> {
|
||||
let mut file = if query.append {
|
||||
match disk.append_file(&query.volume, &query.path).await {
|
||||
Ok(file) => file,
|
||||
Err(e) => return response_with_status(StatusCode::INTERNAL_SERVER_ERROR, format!("append file err {e}")),
|
||||
Err(e) => {
|
||||
let message = put_file_stage_error_message("append", &query, &e);
|
||||
warn!("{message}");
|
||||
return response_with_status(StatusCode::INTERNAL_SERVER_ERROR, message);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
match disk.create_file("", &query.volume, &query.path, query.size).await {
|
||||
Ok(file) => file,
|
||||
Err(e) => return response_with_status(StatusCode::INTERNAL_SERVER_ERROR, format!("create file err {e}")),
|
||||
Err(e) => {
|
||||
let message = put_file_stage_error_message("create", &query, &e);
|
||||
warn!("{message}");
|
||||
return response_with_status(StatusCode::INTERNAL_SERVER_ERROR, message);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let copied = match write_body_chunks_to_writer(req.into_body().into_data_stream(), &mut file).await {
|
||||
Ok(copied) => copied,
|
||||
Err(e) => return response_with_status(StatusCode::INTERNAL_SERVER_ERROR, format!("write file err {e}")),
|
||||
Err(e) => {
|
||||
let message = put_file_stage_error_message("write_body", &query, &e);
|
||||
warn!("{message}");
|
||||
return response_with_status(StatusCode::INTERNAL_SERVER_ERROR, message);
|
||||
}
|
||||
};
|
||||
|
||||
global_internode_metrics().record_incoming_request_for_operation_and_backend(
|
||||
@@ -305,7 +317,9 @@ async fn handle_put_file(req: Request<Incoming>) -> Response<Body> {
|
||||
);
|
||||
|
||||
if let Err(e) = file.flush().await {
|
||||
return response_with_status(StatusCode::INTERNAL_SERVER_ERROR, format!("write file err {e}"));
|
||||
let message = put_file_stage_error_message("flush", &query, &e);
|
||||
warn!("{message}");
|
||||
return response_with_status(StatusCode::INTERNAL_SERVER_ERROR, message);
|
||||
}
|
||||
|
||||
empty_ok()
|
||||
@@ -364,6 +378,13 @@ fn response_with_status(status: StatusCode, message: impl Into<String>) -> Respo
|
||||
.expect("failed to build rpc error response")
|
||||
}
|
||||
|
||||
fn put_file_stage_error_message(stage: &str, query: &PutFileQuery, err: &dyn std::fmt::Display) -> String {
|
||||
format!(
|
||||
"{stage} file err {err} [disk={}, volume={}, path={}, append={}, size={}]",
|
||||
query.disk, query.volume, query.path, query.append, query.size
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@@ -404,6 +425,25 @@ mod tests {
|
||||
assert_eq!(response.status(), StatusCode::FORBIDDEN);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn put_file_stage_error_message_includes_stage_and_request_context() {
|
||||
let query = PutFileQuery {
|
||||
disk: "disk-a".to_string(),
|
||||
volume: ".rustfs.sys/tmp".to_string(),
|
||||
path: "tmp/object/part.1".to_string(),
|
||||
append: false,
|
||||
size: 1024,
|
||||
};
|
||||
|
||||
let msg = put_file_stage_error_message("write_body", &query, &"connection reset");
|
||||
assert!(msg.contains("write_body"));
|
||||
assert!(msg.contains("disk=disk-a"));
|
||||
assert!(msg.contains("volume=.rustfs.sys/tmp"));
|
||||
assert!(msg.contains("path=tmp/object/part.1"));
|
||||
assert!(msg.contains("append=false"));
|
||||
assert!(msg.contains("size=1024"));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn write_body_chunks_to_writer_streams_all_chunks() {
|
||||
let (mut reader, mut writer) = tokio::io::duplex(64);
|
||||
|
||||
Reference in New Issue
Block a user