CAMEL-24153: camel-aws2-s3 - Fix streaming upload truncation and orphaned multipart uploads#24859
Conversation
…aned multipart uploads Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Claus Ibsen <claus.ibsen@gmail.com>
|
🌟 Thank you for your contribution to the Apache Camel project! 🌟 🐫 Apache Camel Committers, please review the following items:
|
gnodet
left a comment
There was a problem hiding this comment.
Claude Code on behalf of gnodet
Solid fix for three distinct data-loss bugs in AWS2S3StreamUploadProducer — each well-analyzed with clear root cause.
Changes verified:
-
maxReadnot reset after batch-flush ✅
AftercompleteUpload(),maxReadstayed at 0 (or whatever it was post-subtraction), sotoByteArray(is, 0)read nothing on the next exchange. Reset topartSizeis correctly applied in all 4 completion sites (2 inprocessWithoutTimestampGrouping, 2 inprocessWithTimestampGrouping), guarded byisMultiPartUpload(). -
createMultipartUploadcalled on every iteration ✅
CAMEL-20728'sstate.index = 1broke theif (state.index == 1)guard — it was always true.if (state.initResponse == null)is a better invariant since it's impossible to regress. Consistently applied to all 3 guarded blocks (random naming, timestamp naming, and the actualcreateMultipartUploadcall). -
maxReadgoing negative ✅
Math.max(1, maxRead)is the right clamp — using 1 instead of 0 ensurestoByteArraystill attempts a read, keeping the loop alive. Applied in bothprocessWithoutTimestampGroupingandprocessWithTimestampGrouping.
Tests:
All 3 tests are well-designed with mocked S3Client:
testBodyLargerThanPartSizeIsNotTruncated— reassembles all uploaded parts and verifies byte-for-byte matchtestCreateMultipartUploadCalledOncePerUpload—verify(times(1))catches the orphan-upload regressiontestMultiplePartsUploadedCorrectly— verifies sequential part numbers and consistentuploadId
No issues found.
|
🧪 CI tested the following changed modules:
🔬 Scalpel shadow comparison — Scalpel: 10 tested, 29 compile-only — current: 10 all testedMaveniverse Scalpel detected 39 affected modules (current approach: 10).
|
Summary
Fixes three bugs in
AWS2S3StreamUploadProducerthat cause data loss and orphaned multipart uploads whenmultiPartUpload=trueand the body is larger thanpartSize:maxReadnot reset after batch-flush: after a batch completion,maxReadstayed at 0, sotoByteArray(is, 0)read nothing and the loop exited with remaining data unread. AddedmaxRead = partSizereset (guarded byisMultiPartUpload()) in bothprocessWithoutTimestampGroupingandprocessWithTimestampGrouping.createMultipartUploadcalled on every iteration: CAMEL-20728 changedstate.index++tostate.index = 1, breaking theif (state.index == 1)guard socreateMultipartUploadfired on every loop iteration. Each call returned a newuploadId, orphaning parts from earlier iterations and accruing storage charges. Changed guard toif (state.initResponse == null).maxReadgoing negative: whenuploadAggregate.buffer.size() > partSize, subtracting it frommaxReaddrovemaxReadnegative, silently dropping the next exchange body. AddedMath.max(1, maxRead)clamp.Test plan
AWS2S3StreamUploadMultipartTestwith 3 unit tests (mocked S3Client):partSizeis not truncatedcreateMultipartUploadcalled exactly once per uploadS3StreamUploadMultipartITandS3StreamUploadMultipartAsyncIT)Claude Code on behalf of davsclaus
Co-Authored-By: Claude Opus 4.6 noreply@anthropic.com