Skip to content

Commit 80f8a6d

Browse files
HJLebbinkTest User
authored andcommitted
added CRC32, CRC32C, SHA1, SHA256 and CRC64NVME
1 parent 2e94a0e commit 80f8a6d

17 files changed

+1666
-17
lines changed

Cargo.toml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ async-trait = "0.1"
4040
base64 = "0.22"
4141
chrono = { version = "0.4", features = ["serde"] }
4242
crc = "3.3"
43+
crc32c = "0.6"
44+
crc32fast = "1.4"
4345
dashmap = "6.1.0"
4446
env_logger = "0.11"
4547
hmac = { version = "0.12", optional = true }
@@ -55,6 +57,7 @@ ring = { version = "0.17", optional = true, default-features = false, features =
5557
serde = { version = "1.0", features = ["derive"] }
5658
serde_json = "1.0"
5759
serde_yaml = "0.9"
60+
sha1 = "0.10"
5861
sha2 = { version = "0.10", optional = true }
5962
urlencoding = "2.1"
6063
xmltree = "0.12"
@@ -95,3 +98,8 @@ name = "load_balancing_with_hooks"
9598
name = "s3-api"
9699
path = "benches/s3/api_benchmarks.rs"
97100
harness = false
101+
102+
[[bench]]
103+
name = "bench_checksums"
104+
path = "benches/bench_checksums.rs"
105+
harness = false

benches/bench_checksums.rs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// MinIO Rust Library for Amazon S3 Compatible Cloud Storage
2+
// Copyright 2025 MinIO, Inc.
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
//
8+
// http://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS,
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
16+
use criterion::{Criterion, Throughput, criterion_group, criterion_main};
17+
use minio::s3::utils::{crc32_checksum, crc32c, crc64nvme_checksum, sha1_hash, sha256_checksum};
18+
19+
fn bench_checksums(c: &mut Criterion) {
20+
let sizes = vec![
21+
("1KB", 1024),
22+
("10KB", 10 * 1024),
23+
("100KB", 100 * 1024),
24+
("1MB", 1024 * 1024),
25+
("10MB", 10 * 1024 * 1024),
26+
];
27+
28+
for (name, size) in sizes {
29+
let data = vec![0u8; size];
30+
31+
let mut group = c.benchmark_group(format!("checksum_{}", name));
32+
group.throughput(Throughput::Bytes(size as u64));
33+
34+
group.bench_function("CRC32", |b| b.iter(|| crc32_checksum(&data)));
35+
36+
group.bench_function("CRC32C", |b| b.iter(|| crc32c(&data)));
37+
38+
group.bench_function("CRC64NVME", |b| b.iter(|| crc64nvme_checksum(&data)));
39+
40+
group.bench_function("SHA1", |b| b.iter(|| sha1_hash(&data)));
41+
42+
group.bench_function("SHA256", |b| b.iter(|| sha256_checksum(&data)));
43+
44+
group.finish();
45+
}
46+
}
47+
48+
criterion_group!(benches, bench_checksums);
49+
criterion_main!(benches);

src/s3/builders/append_object.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,14 @@ pub struct AppendObject {
6464
#[builder(!default)] // force required
6565
/// value of x-amz-write-offset-bytes
6666
offset_bytes: u64,
67+
68+
/// Optional checksum algorithm for data integrity verification during append.
69+
///
70+
/// When specified, computes a checksum of the appended data using the selected algorithm
71+
/// (CRC32, CRC32C, SHA1, SHA256, or CRC64NVME). The checksum is sent with the append
72+
/// operation and verified by the server.
73+
#[builder(default, setter(into))]
74+
checksum_algorithm: Option<crate::s3::utils::ChecksumAlgorithm>,
6775
}
6876

6977
impl S3Api for AppendObject {
@@ -83,6 +91,7 @@ pub type AppendObjectBldr = AppendObjectBuilder<(
8391
(),
8492
(Arc<SegmentedBytes>,),
8593
(u64,),
94+
(),
8695
)>;
8796

8897
impl ToS3Request for AppendObject {
@@ -94,6 +103,24 @@ impl ToS3Request for AppendObject {
94103
let mut headers: Multimap = self.extra_headers.unwrap_or_default();
95104
headers.add(X_AMZ_WRITE_OFFSET_BYTES, self.offset_bytes.to_string());
96105

106+
if let Some(algorithm) = self.checksum_algorithm {
107+
use crate::s3::header_constants::*;
108+
use crate::s3::utils::{ChecksumAlgorithm, compute_checksum_sb};
109+
110+
let checksum_value = compute_checksum_sb(algorithm, &self.data);
111+
headers.add(X_AMZ_CHECKSUM_ALGORITHM, algorithm.as_str().to_string());
112+
113+
match algorithm {
114+
ChecksumAlgorithm::CRC32 => headers.add(X_AMZ_CHECKSUM_CRC32, checksum_value),
115+
ChecksumAlgorithm::CRC32C => headers.add(X_AMZ_CHECKSUM_CRC32C, checksum_value),
116+
ChecksumAlgorithm::SHA1 => headers.add(X_AMZ_CHECKSUM_SHA1, checksum_value),
117+
ChecksumAlgorithm::SHA256 => headers.add(X_AMZ_CHECKSUM_SHA256, checksum_value),
118+
ChecksumAlgorithm::CRC64NVME => {
119+
headers.add(X_AMZ_CHECKSUM_CRC64NVME, checksum_value)
120+
}
121+
}
122+
}
123+
97124
Ok(S3Request::builder()
98125
.client(self.client)
99126
.method(Method::PUT)
@@ -144,6 +171,13 @@ pub struct AppendObjectContent {
144171
/// Value of x-amz-write-offset-bytes
145172
#[builder(default)]
146173
offset_bytes: u64,
174+
/// Optional checksum algorithm for data integrity verification during append.
175+
///
176+
/// When specified, computes checksums for appended data using the selected algorithm
177+
/// (CRC32, CRC32C, SHA1, SHA256, or CRC64NVME). The checksum is computed for each
178+
/// chunk and sent with the append operation.
179+
#[builder(default, setter(into))]
180+
checksum_algorithm: Option<crate::s3::utils::ChecksumAlgorithm>,
147181
}
148182

149183
/// Builder type for [`AppendObjectContent`] that is returned by [`MinioClient::append_object_content`](crate::s3::client::MinioClient::append_object_content).
@@ -162,6 +196,7 @@ pub type AppendObjectContentBldr = AppendObjectContentBuilder<(
162196
(),
163197
(),
164198
(),
199+
(),
165200
)>;
166201

167202
impl AppendObjectContent {
@@ -229,6 +264,7 @@ impl AppendObjectContent {
229264
offset_bytes: current_file_size,
230265
sse: self.sse,
231266
data: Arc::new(seg_bytes),
267+
checksum_algorithm: self.checksum_algorithm,
232268
};
233269
ao.send().await
234270
} else if let Some(expected) = object_size.value()
@@ -296,6 +332,7 @@ impl AppendObjectContent {
296332
sse: self.sse.clone(),
297333
data: Arc::new(part_content),
298334
offset_bytes: next_offset_bytes,
335+
checksum_algorithm: self.checksum_algorithm,
299336
};
300337
let resp: AppendObjectResponse = append_object.send().await?;
301338
//println!("AppendObjectResponse: object_size={:?}", resp.object_size);

src/s3/builders/copy_object.rs

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,12 @@ use crate::s3::response::{
2323
CopyObjectInternalResponse, CopyObjectResponse, CreateMultipartUploadResponse,
2424
StatObjectResponse, UploadPartCopyResponse,
2525
};
26-
use crate::s3::response_traits::HasEtagFromBody;
26+
use crate::s3::response_traits::{HasChecksumHeaders, HasEtagFromBody};
2727
use crate::s3::sse::{Sse, SseCustomerKey};
2828
use crate::s3::types::{Directive, PartInfo, Retention, S3Api, S3Request, ToS3Request};
2929
use crate::s3::utils::{
30-
UtcTime, check_bucket_name, check_object_name, check_sse, check_ssec, to_http_header_value,
31-
to_iso8601utc, url_encode,
30+
ChecksumAlgorithm, UtcTime, check_bucket_name, check_object_name, check_sse, check_ssec,
31+
to_http_header_value, to_iso8601utc, url_encode,
3232
};
3333
use async_recursion::async_recursion;
3434
use http::Method;
@@ -59,6 +59,13 @@ pub struct UploadPartCopy {
5959
part_number: u16,
6060
#[builder(default)]
6161
headers: Multimap,
62+
/// Optional checksum algorithm for data integrity verification during part copy.
63+
///
64+
/// When specified, the server computes a checksum of the copied part data using
65+
/// this algorithm. Use the same algorithm for all parts in a multipart upload.
66+
/// Supported algorithms: CRC32, CRC32C, SHA1, SHA256, CRC64NVME.
67+
#[builder(default, setter(into))]
68+
checksum_algorithm: Option<crate::s3::utils::ChecksumAlgorithm>,
6269
}
6370

6471
impl S3Api for UploadPartCopy {
@@ -78,6 +85,7 @@ pub type UploadPartCopyBldr = UploadPartCopyBuilder<(
7885
(String,),
7986
(),
8087
(),
88+
(),
8189
)>;
8290

8391
impl ToS3Request for UploadPartCopy {
@@ -100,6 +108,10 @@ impl ToS3Request for UploadPartCopy {
100108
let mut headers: Multimap = self.extra_headers.unwrap_or_default();
101109
headers.add_multimap(self.headers);
102110

111+
if let Some(algorithm) = self.checksum_algorithm {
112+
headers.add(X_AMZ_CHECKSUM_ALGORITHM, algorithm.as_str().to_string());
113+
}
114+
103115
let mut query_params: Multimap = self.extra_query_params.unwrap_or_default();
104116
{
105117
query_params.add("partNumber", self.part_number.to_string());
@@ -150,6 +162,8 @@ pub struct CopyObjectInternal {
150162
metadata_directive: Option<Directive>,
151163
#[builder(default, setter(into))]
152164
tagging_directive: Option<Directive>,
165+
#[builder(default, setter(into))]
166+
checksum_algorithm: Option<crate::s3::utils::ChecksumAlgorithm>,
153167
}
154168

155169
impl S3Api for CopyObjectInternal {
@@ -175,6 +189,7 @@ pub type CopyObjectInternalBldr = CopyObjectInternalBuilder<(
175189
(),
176190
(),
177191
(),
192+
(),
178193
)>;
179194

180195
impl ToS3Request for CopyObjectInternal {
@@ -261,6 +276,10 @@ impl ToS3Request for CopyObjectInternal {
261276
if let Some(v) = self.source.ssec {
262277
headers.add_multimap(v.copy_headers());
263278
}
279+
280+
if let Some(algorithm) = self.checksum_algorithm {
281+
headers.add(X_AMZ_CHECKSUM_ALGORITHM, algorithm.as_str().to_string());
282+
}
264283
};
265284

266285
Ok(S3Request::builder()
@@ -310,6 +329,13 @@ pub struct CopyObject {
310329
metadata_directive: Option<Directive>,
311330
#[builder(default, setter(into))]
312331
tagging_directive: Option<Directive>,
332+
/// Optional checksum algorithm for data integrity verification during copy.
333+
///
334+
/// When specified, the server computes a checksum of the destination object using
335+
/// this algorithm during the copy operation. Supported algorithms: CRC32, CRC32C,
336+
/// SHA1, SHA256, CRC64NVME. The checksum value is included in response headers for verification.
337+
#[builder(default, setter(into))]
338+
checksum_algorithm: Option<crate::s3::utils::ChecksumAlgorithm>,
313339
}
314340

315341
/// Builder type for [`CopyObject`] that is returned by [`MinioClient::copy_object`](crate::s3::client::MinioClient::copy_object).
@@ -331,6 +357,7 @@ pub type CopyObjectBldr = CopyObjectBuilder<(
331357
(),
332358
(),
333359
(),
360+
(),
334361
)>;
335362

336363
impl CopyObject {
@@ -434,6 +461,7 @@ impl CopyObject {
434461
.source(self.source)
435462
.metadata_directive(self.metadata_directive)
436463
.tagging_directive(self.tagging_directive)
464+
.checksum_algorithm(self.checksum_algorithm)
437465
.build()
438466
.send()
439467
.await?;
@@ -629,6 +657,11 @@ impl ComposeObjectInternal {
629657
number: part_number,
630658
etag,
631659
size,
660+
checksum_crc32: resp.get_checksum(ChecksumAlgorithm::CRC32),
661+
checksum_crc32c: resp.get_checksum(ChecksumAlgorithm::CRC32C),
662+
checksum_sha1: resp.get_checksum(ChecksumAlgorithm::SHA1),
663+
checksum_sha256: resp.get_checksum(ChecksumAlgorithm::SHA256),
664+
checksum_crc64nvme: resp.get_checksum(ChecksumAlgorithm::CRC64NVME),
632665
});
633666
} else {
634667
while size > 0 {
@@ -669,6 +702,11 @@ impl ComposeObjectInternal {
669702
number: part_number,
670703
etag,
671704
size,
705+
checksum_crc32: resp.get_checksum(ChecksumAlgorithm::CRC32),
706+
checksum_crc32c: resp.get_checksum(ChecksumAlgorithm::CRC32C),
707+
checksum_sha1: resp.get_checksum(ChecksumAlgorithm::SHA1),
708+
checksum_sha256: resp.get_checksum(ChecksumAlgorithm::SHA256),
709+
checksum_crc64nvme: resp.get_checksum(ChecksumAlgorithm::CRC64NVME),
672710
});
673711

674712
offset += length;

0 commit comments

Comments
 (0)