Skip to content

fix: UploadPartCopy passthrough + copy pipeline memory cap#115

Merged
ServerSideHannes merged 6 commits into
mainfrom
fix/copy-hold-reservation-and-pipeline-cap
Jul 7, 2026
Merged

fix: UploadPartCopy passthrough + copy pipeline memory cap#115
ServerSideHannes merged 6 commits into
mainfrom
fix/copy-hold-reservation-and-pipeline-cap

Conversation

@ServerSideHannes

@ServerSideHannes ServerSideHannes commented Jul 7, 2026

Copy link
Copy Markdown
Owner

Summary

  • UploadPartCopy passthrough: same-credential encrypted dedup copies use native upload_part_copy per internal part with source DEK adoption — no download/decrypt/re-encrypt amplification (root cause of s3proxy OOM during Scylla backup dedup)
  • Hold governor reservation through upload_part (release after del ciphertext), so tracked memory matches RSS during S3 I/O
  • Default S3PROXY_MAX_PARALLEL_COPIES=2 semaphore: max 2 streaming copy pipelines per pod
  • Exhaustive e2e CI suite (test_upload_part_copy_passthrough_e2e.py): 8 tests on real s3proxy subprocess + MinIO — zero encrypt, ciphertext byte-identity on MinIO, DEK adoption, 1280MB Scylla scale, 10 concurrent copies under 192MB budget

UploadPartCopy passthrough

  • Eligible when: encrypted source with multipart sidecar metadata, full-object copy (no CopySourceRange), same kid
  • Adopts source DEK; byte-copies ciphertext via server-side upload_part_copy
  • Range copies and re-key cases still use existing re-encrypt paths

Verification

E2E passthrough suite (memory_copy shard)

Test Proves
test_zero_encrypt_and_low_memory 0 MB encrypted, peak << 88MB/chunk
test_ciphertext_byte_identical_on_minio Raw MinIO bytes identical (native copy)
test_dek_adoption_in_sidecar wrapped_dek + internal part layout preserved
test_range_copy_reencrypts_with_high_memory Control: range forces re-encrypt
test_scylla_scale_passthrough 1280MB passthrough, ciphertext identical
test_ten_concurrent_passthrough_copies 10 parallel copies under 192MB budget
make verify-passthrough   # same 8 tests locally
make test-integration-shard SHARD=memory_copy

Unit

  • test_upload_part_copy_passthrough.py — mock round-trip + server-side path
  • test_copy_pipeline_cap.py — pipeline semaphore + governor bounds

Test plan

  • 8 passthrough e2e tests pass locally (~2.5 min)
  • Unit copy suite green
  • CI memory_copy shard
  • Deploy; confirm Scylla Failed stops tracking Deduplicated, no s3proxy OOM during dedup

ServerSideHannes and others added 2 commits July 7, 2026 10:51
Release-before-upload left ~300MB untracked RSS per pod while the governor
counted ~177MB, causing OOM and Scylla dedup failures. Hold reservation
through upload_part, default max 2 concurrent copy pipelines per pod, and
add Scylla-shaped load tests (13 concurrent copies, subprocess Prometheus).

Co-authored-by: Cursor <cursoragent@cursor.com>
Native upload_part_copy per internal part with source DEK adoption avoids
download/decrypt/re-encrypt during Scylla Manager dedup, which was OOMing
s3proxy under concurrent UploadPartCopy floods.

Co-authored-by: Cursor <cursoragent@cursor.com>
@ServerSideHannes ServerSideHannes changed the title fix: cap copy pipelines and hold memory through upload fix: UploadPartCopy passthrough + copy pipeline memory cap Jul 7, 2026
ServerSideHannes and others added 4 commits July 7, 2026 15:31
Passthrough still acquires copy_pipeline_peak reservation and the pipeline
semaphore so concurrent copies get SlowDown under a tight budget (memory_copy
CI). Clean up ruff SIM108/F401 in passthrough tests.

Co-authored-by: Cursor <cursoragent@cursor.com>
Only passthrough UploadPartCopy when the source has multipart metadata
(Scylla dedup SSTs); large PutObject blobs keep the streaming re-encrypt
path so memory_copy governor/sawtooth tests stay valid. Use lightweight
per-segment governor slots for native copies. Align except syntax with
ruff format on py314.

Co-authored-by: Cursor <cursoragent@cursor.com>
Three concurrent large copies serialize on S3PROXY_MAX_PARALLEL_COPIES=2
instead of getting SlowDown from the memory governor. Assert all finish
without OOM rather than expecting a rejection.

Co-authored-by: Cursor <cursoragent@cursor.com>
Extract shared verification into passthrough_verify.py with 8 pytest
cases (96MB + 1280MB + 10 concurrent copies). Runs in memory_copy shard;
make verify-passthrough wraps the same tests.

Co-authored-by: Cursor <cursoragent@cursor.com>
@ServerSideHannes ServerSideHannes merged commit 6cab35d into main Jul 7, 2026
10 checks passed
@ServerSideHannes ServerSideHannes deleted the fix/copy-hold-reservation-and-pipeline-cap branch July 7, 2026 15:49
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.

1 participant