fix(folders): clean up blobs on recursive delete without destroying live citations (#177) - #214
Merged
Merged
Conversation
This was referenced Sep 17, 2026
Collaborator
Author
|
Pushed a test-only follow-up (
PR body now also has |
Collaborator
Author
|
Follow-up I cannot approve this PR: last push is mine. Needs another CODEOWNER after CI is green. |
Collaborator
Author
|
Waiting on CI for |
Collaborator
Author
|
请评审合入(作者是我,不能自批)。
需要 @PeterGuy326 或 @Bindy-lbb 作为非作者 CODEOWNER 批准后才能进 main。 |
PeterGuy326
approved these changes
Sep 18, 2026
Recursive folder delete removed DB rows but left every underlying object in bucket storage. The code had an explicit TODO acknowledging this. Changes: - Add ObjectStore and logger options to folder.Service (WithStore, WithLogger) - Collect storage keys before deleting files, then delete blobs after the transaction commits (best-effort, matching file.Delete's shape) - Log failed blob deletions at WARN level so operators can see orphans - Update memd wiring to pass store and logger to folder service - Add integration tests verifying blob cleanup and backward compatibility - Document object retention behavior in DEPLOYMENT.md - Add CHANGELOG entry The crash window (process killed between commit and blob delete) is documented as a known gap. A reaper would need to record keys whose delete was never attempted, since storage.Store has no listing.
Recursive blob cleanup would otherwise destroy objects still cited by active/archived memories whose path is outside the folder, because source_file_id is ON DELETE SET NULL.
Recursive-delete tests must lock a resource-owner workspace, insert memories with idempotency_key_sha256, and keep source_file_id on the session-local memories shadow table.
…columns PostgreSQL 42P08: $3 was bound to source_file_sha256 (text) and idempotency_key_sha256 (char(64)) at once.
PeterGuy326
force-pushed
the
fix/177-folder-delete-source-guard
branch
from
September 18, 2026 02:59
e7e5bba to
91166d3
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Refs #177
Requirement and scope
Successor to #210 for #177. Keeps the original blob-cleanup implementation and answers the remaining review request: recursive delete must not physically destroy an object still cited by an active/archived memory whose
pathis outside the folder.files.storage_keyremains per-row (users/<user_id>/<file_id>/<basename>), so unconditional key delete is still safe across file rows. The new hole wasmemories.source_file_id … ON DELETE SET NULL: a memory at/Work/taskciting a file under/Photoswould previously pass the path-only guard, the file row would vanish, the FK would null out, and this PR's blob cleanup would then make the cited bytes unrecoverable.Changes
containsMemoriesTxalso matchessource_file_idagainst files in the deleted tree (folder_idor literal path prefix). Hit → existingErrContainsMemories(forget first).TestRecursiveDeleteBlocksWhenMemoryCitesFileElsewhere.docs/DEPLOYMENT.mdand[Unreleased]changelog record the citation guard.Original blob-cleanup work and contributor credit: @xiaocui-big via #210. This successor does not close #210 or #177 automatically.
Validation ledger
gofmt+go test ./internal/folderMEM_TEST_DB=…_test go test ./internal/folder -run TestRecursiveDeleteBlocksWhenMemoryCitesFileElsewhere_testdatabase in this environmentmake test-servergit diff --checkRisk / rollback
Recursive delete of a folder whose files are still cited by live memories now fails closed instead of deleting the blobs. Revert this branch to restore path-only guarding (and, if #210 is also reverted, orphan blobs on recursive delete).
No merge, release, or issue closure is claimed.