Skip to content

Combine per-part CRCs for whole-object download checksum validation - #663

Merged
TingDaoK merged 12 commits into
mainfrom
checksum-combine
Aug 6, 2026
Merged

Combine per-part CRCs for whole-object download checksum validation#663
TingDaoK merged 12 commits into
mainfrom
checksum-combine

Conversation

@TingDaoK

@TingDaoK TingDaoK commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Problem

When a multipart download validates a whole-object checksum, that checksum could only be
built by feeding the object's bytes into a single running checksum in object order. The work
happened in the delivery loop on the meta request's io_event_loop thread, so when the delivery
is the bottleneck, this added extra cost to the critical path and impacts the overall performance.

Change

CRCs compose: given the digests of two adjacent blocks and the length of the second, the
digest of their concatenation follows in O(1). So for the CRC algorithms each part now
digests its own body on its own connection thread, and the whole-object checksum is assembled
from those per-part digests when the meta request finishes.

Non-combinable algorithms (SHA*, XXHASH*) are unchanged — they still accumulate byte-wise in
the delivery loop, which is what guarantees object order for them.


Moved away from ubuntu 18 for gcc 13, it keeps failing with an unknown crash in libc. I have no idea what is causing the crash. But, since we know that there are fixes for later version of gcc that is not port back to old version of ubuntu, #479, so I decided to try move ubuntu 22 for gcc 13. And it seems to work. :-)

TODO

This can be used for the upload path to provide the full object level checksum to s3.

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.

@codecov-commenter

codecov-commenter commented Aug 3, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 83.46457% with 21 lines in your changes missing coverage. Please review.
✅ Project coverage is 89.11%. Comparing base (0c26c42) to head (438f4ac).

Files with missing lines Patch % Lines
source/s3_meta_request.c 82.29% 17 Missing ⚠️
source/s3_checksums.c 89.65% 3 Missing ⚠️
source/s3_auto_ranged_get.c 50.00% 1 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main     #663      +/-   ##
==========================================
- Coverage   89.14%   89.11%   -0.03%     
==========================================
  Files          23       23              
  Lines        8044     8160     +116     
==========================================
+ Hits         7171     7272     +101     
- Misses        873      888      +15     
Files with missing lines Coverage Δ
source/s3_auto_ranged_get.c 95.56% <50.00%> (-0.22%) ⬇️
source/s3_checksums.c 85.44% <89.65%> (+1.49%) ⬆️
source/s3_meta_request.c 90.17% <82.29%> (-0.49%) ⬇️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@TingDaoK TingDaoK changed the title combine checksums Combine per-part CRCs for whole-object download checksum validation Aug 3, 2026
@TingDaoK
TingDaoK marked this pull request as ready for review August 3, 2026 22:54
Comment thread include/aws/s3/private/s3_checksums.h Outdated
* Folds the digest of one data block into `head`, so that `head` becomes the checksum of its own data
* followed by that block, without re-scanning either:
*
* head = checksum(block_head) (still running, not finalized)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: this threw me in for a loop. technically this works because our crc impl is just always in finalized state and the finalize call in s3 code does not do anything.
in general in would not be valid to combine finalized and non-finalized crcs as it would produce wrong result

*
* Only worth calling for multipart downloads; with a single request there are no parts to combine. */
AWS_S3_API
int aws_s3_meta_request_setup_checksum_combine_synced(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we know the timings on this? if needed we can probably speed it up further

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[checksum-combine] 9363 combines in 3.293 ms file(s) remaining
[checksum-combine] 65536 combines in 21.310 msile(s) remaining 

~350ns per combine operations. So, for the case of small part size on large object, it took 20ms, but not i'd say to be a concern here.

Comment thread source/s3_checksums.c

/* The CRC finalizers write digests big-endian, so read them back the same way. */
uint64_t tail_value = 0;
if (head->digest_size == AWS_CRC32_LEN) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

potential optimization idea for future: but for gets we never need to finalize to be and then back. thats needed purely for puts

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, mostly because our current aws_s3_checksum interface is a pointer tied with the request itself, so I want to keep the parts level checksum independent from the request without affecting the lifetime of the request itself to keep it simple.

And the interface only has the checksum_finalize that provides the encoded checksum. and I keep a list of the finalized one with the meta request.

But, the extra encode/decode should be trivial, we can optimize it if we need to.

@TingDaoK
TingDaoK merged commit 226c3e6 into main Aug 6, 2026
75 of 76 checks passed
@TingDaoK
TingDaoK deleted the checksum-combine branch August 6, 2026 17:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants