Skip to content

Fix copy endpoint for files >5 GB (PTFE-3441) - #221

Merged
matthiasL-scality merged 4 commits into
mainfrom
PTFE-3441-fix-copy-large-files
Aug 6, 2026
Merged

Fix copy endpoint for files >5 GB (PTFE-3441)#221
matthiasL-scality merged 4 commits into
mainfrom
PTFE-3441-fix-copy-large-files

Conversation

@matthiasL-scality

@matthiasL-scality matthiasL-scality commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Root cause: copy_build.lua uses S3 CopyObject (x-amz-copy-source) for every file with no size check. Scaleway enforces a 5 GB hard limit (identical to AWS S3). Builds with files >5 GB (e.g. artesca promote jobs) fail with EntityTooLarge.
  • Fix: On EntityTooLarge (HTTP 400), fall back to multipart copy using S3 UploadPartCopy. Parts are sized at max(5 MB, ⌈size/1000⌉) to stay within Scaleway's 1,000-part limit. Parts within a single file are copied in parallel batches of 16.
  • Test coverage: COPY_OBJECT_SIZE_LIMIT=0 added to tests/.env forces all non-empty files through the multipart code path in CI, so the full initiate→part→complete cycle is exercised without actual >5 GB files.

Changes

File Change
conf/nginx.conf.template env COPY_OBJECT_SIZE_LIMIT; + 4 internal-only locations: copy-multipart-{initiate,part,complete,abort}
lua/compute_aws_s3_signature.lua 4 new signature modes: COPY_MULTIPART_{INITIATE,PART,COMPLETE,ABORT}
lua/copy_build.lua multipart_copy() function; production path falls back on EntityTooLarge; test path uses size threshold
tests/.env COPY_OBJECT_SIZE_LIMIT=0 to force multipart in CI
tests/end2end/test_copy.py test_copy_via_multipart_copy verifies content integrity through the multipart path

Test plan

  • CI passes — all existing test_copy.py tests now run through the multipart path (due to COPY_OBJECT_SIZE_LIMIT=0) and verify the implementation is correct end-to-end
  • New test test_copy_via_multipart_copy specifically documents and asserts the multipart behavior
  • Manual verification: deploy to a Scaleway-backed environment and promote a build containing a file >5 GB

Fixes: PTFE-3441

🤖 Generated with Claude Code

Scaleway enforces a 5GB hard limit on CopyObject (identical to AWS S3).
Builds containing files >5GB (e.g. artesca promote jobs) fail with
EntityTooLarge when copy_build.lua tries to copy them in a single
CopyObject call.

Production path: attempt CopyObject as before; on 400 EntityTooLarge
fall back to multipart copy (UploadPartCopy), using up to 1,000 parts
(Scaleway limit) with a minimum 5 MB part size.

Test path: COPY_OBJECT_SIZE_LIMIT=0 in tests/.env forces all non-empty
files through the multipart path so the UploadPartCopy code is exercised
in CI without needing actual >5 GB files.

Four new internal-only nginx locations handle the multipart lifecycle
(initiate/part/complete/abort), and four matching signature modes are
added to compute_aws_s3_signature.lua.

Fixes: PTFE-3441

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@matthiasL-scality
matthiasL-scality requested a review from a team as a code owner August 6, 2026 09:08
Comment thread lua/copy_build.lua Outdated
@claude

claude Bot commented Aug 6, 2026

Copy link
Copy Markdown
  • S3 CompleteMultipartUpload can return HTTP 200 with an error in the XML body, causing multipart_copy() to silently report success for an incomplete object
    - Add complete_res.body:find("<Error>", 1, true) to the status check on line 170, matching how initiate/part responses are already validated via body content

    Review by Claude Code

All 4 multipart copy subrequests (initiate, part, complete, abort)
were calling their nginx locations directly, causing the
`if ($remote_addr != 127.0.0.1) { return 400; }` guard to fire
because ngx.location.capture inherits the parent request's remote_addr
(the external client IP), not 127.0.0.1.

Prefix all calls with /force_real_request/ so they proxy through
nginx to localhost, making $remote_addr == 127.0.0.1 as required.
This mirrors the existing pattern used by /force_real_request/copy/.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Comment thread lua/copy_build.lua Outdated
@claude

claude Bot commented Aug 6, 2026

Copy link
Copy Markdown
  • lua/copy_build.lua:172 — abort after complete failure is missing the /force_real_request/ prefix, so the subrequest inherits the external client's $remote_addr and the copy-multipart-abort location returns 400, leaving orphaned multipart parts on S3
    • Add the /force_real_request/ prefix to match all other subrequest calls in the function

Review by Claude Code

Two fixes from code review:
- Add /force_real_request/ prefix on the abort call inside the
  complete-failure handler (different indentation was missed by
  the previous replace_all pass)
- Check for <Error> in the CompleteMultipartUpload response body:
  S3 can return HTTP 200 with an error payload (documented behavior)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@claude

claude Bot commented Aug 6, 2026

Copy link
Copy Markdown

LGTM

Multipart copy implementation is solid. Error handling properly aborts in-flight uploads on every failure path, preventing orphaned parts. Part sizing correctly respects both the 5 MB S3 minimum and Scaleway's 1,000-part cap. Signature construction follows the existing COPY mode patterns. Test coverage is good — the COPY_OBJECT_SIZE_LIMIT=0 trick exercises the full initiate/part/complete cycle, and per-test bucket isolation (managed_buckets fixture) keeps tests independent.

Review by Claude Code

In test mode (COPY_OBJECT_SIZE_LIMIT set), the server said 'DONE'
for both CopyObject and multipart paths — making it impossible to
tell from the log which was used.  Add '(multipart copy)' suffix
so logCopyOutput in action-artifacts can detect and report it.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@claude

claude Bot commented Aug 6, 2026

Copy link
Copy Markdown

LGTM

Review by Claude Code

@matthiasL-scality
matthiasL-scality merged commit 594749c into main Aug 6, 2026
6 checks passed
@matthiasL-scality
matthiasL-scality deleted the PTFE-3441-fix-copy-large-files branch August 6, 2026 12:04
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.

2 participants