Skip to content

perf(storage): delete a book's file without copying it first - #54

Merged
GianniCarlo merged 1 commit into
mainfrom
chore/drop-delete-support-copy
Sep 30, 2026
Merged

GianniCarlo merged 1 commit into
mainfrom
chore/drop-delete-support-copy

Conversation

@GianniCarlo

Copy link
Copy Markdown
Contributor

Why

Deleting a book's file did three steps inside the request:

  1. copy it to deleted_<key>, a support copy that the remove-deleted-items lifecycle rule expired after 3 days;
  2. delete the original;
  3. answer.

With multipart uploads, books of several GB are now common. For a 3 GB book the server-side copy held the delete for about a minute, and the apps' serial sync queue waited behind it, so a delete looked stuck.

Seen in the iOS device pass: a 3.02 GiB book's delete took about a minute, and its support copy was written as it finished. The copy hasn't been needed for support in a long while.

What

After this deploys, the remove-deleted-items lifecycle rule has nothing to act on once the existing deleted_ copies expire, within 3 days. It can then be removed from the bucket; it's harmless if left.

Tests

  • deleteFile sends exactly one DeleteObject and copies nothing.
  • A delete that S3 refuses answers null.
  • The tests built around the support copy are removed.
  • 459 tests on Postgres 17.
  • Device pass, with the local API on this branch against production: a 326 MB book and a 78 MB book deleted from the app cleared at once. Their rows went inactive, the objects are gone, and no deleted_ copies were made.

Deleting a book first copied its file to a `deleted_` prefix, a support
copy that a lifecycle rule expired after 3 days, and only then deleted
it, all inside the request. With multipart uploads, books of several GB
are common. For a 3 GB book, the server-side copy held the delete for
about a minute, and the apps' serial sync queue waited behind it. The
copy hasn't been needed for support in a long while, so it's gone: the
delete is one DeleteObject.

The 5 GiB fallback that skipped the copy for larger books goes with it.
@github-actions

Copy link
Copy Markdown

✅ Claude PR Review — PASS

Makes S3Service.deleteFile send a single DeleteObjectCommand and drops the deleted_ support copy, the >5 GiB HEAD fallback, and their tests. No routes, middleware, or authorization logic change. Callers (LibraryService book and folder deletes, MultipartUploadService) are unchanged and still pass keys they build themselves, so key scoping is unaffected. The error path still logs with a stripped key and returns null. No IAP or passkey code is involved. Worth knowing: without the support copy, deleted books can't be recovered unless the bucket has versioning, which the PR says is intended.

Findings: no findings

Converged: nothing new this round, and no earlier finding is open.

Model claude-opus-5-5 · run log · 0 new · 0 carried over · 0 resolved · advisory (a human should still review). Findings are de-duplicated across pushes; an earlier finding closes only when the verification pass judges it against the current code — fixed, no longer applicable, accepted by a maintainer, or a duplicate of a finding reported on this push.

@GianniCarlo
GianniCarlo merged commit e37a901 into main Sep 30, 2026
4 checks passed

This branch was successfully deployed

1 active deployment
reviewer — 71341600 Deployed Sep 30, 2026 by GianniCarlo via review #109
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