Skip to content

PR6: Blob-storage reclaim GC - #90

Closed
Diego Colombo (colombod) wants to merge 1 commit into
feat/lease-store-and-storage-guardfrom
feat/blob-reclaim-gc
Closed

PR6: Blob-storage reclaim GC#90
Diego Colombo (colombod) wants to merge 1 commit into
feat/lease-store-and-storage-guardfrom
feat/blob-reclaim-gc

Conversation

@colombod

Copy link
Copy Markdown
Collaborator

Last of the progressive split of #79. Stacks on PR4 (#89) → PR3 (#88) → PR2 (#87) → PR1 (#85) → #81#78.

Delivers

  • /admin/blobs/reclaim — a focused orphaned-blob garbage collector, dormant unless an operator calls it. Safety gates: graph-wide reference scan over the blob-carrier allowlist · not-live (registry.active_sessions) + durable is_fully_drained · hard 15-minute min-age floor · fenced delete(uri, if_unmodified=ref) · destructive-apply single-flight (409 on overlap) · required max_delete when applying · dry_run=true default; the apply path does its own fresh authoritative rescan; one audit line per delete (URI only).
  • Blob-carrier allowlist (blob_processor.py) — folded here because reclaim is its only consumer; a passive mint-time tripwire on an already-registered field.
  • Fixes the admin.py docstring path-leak (raw fs path → the ci-blob:// URI abstraction).

Storage-agnosticism (verified by reading, not just the guard)

  • Protocol-only: zero glob/os.unlink/Path/shutil in shipped code. Enumerate via blob_store.scan() (streams BlobReference), delete via the fenced blob_store.delete(uri, if_unmodified=ref). Reclaims blob-store artifacts only — never the queue/identity/lease stores or graph data. The PR4 storage-boundary guard stays green.

Scope

  • Reclaim GC only. No maintenance-mode / auto-repair / migrations (Phase-2), no cursor/queue (PR1), no working_dir/schema-version (PR2/PR3), no lease/session_keys (PR4) — diff grep-verified clean.

Surface

  • New reclaim endpoint → version 7.3.0 → 7.4.0 + CHANGELOG.

Verification

  • Non-Neo4j suite pass (0 fail), incl. reclaim endpoint + carrier-allowlist (17 tests) and the PR4 storage-boundary guard still green (26); real-Neo4j reclaim E2E passes on a live container; boot smoke green (/version → 7.4.0, dry-run /admin/blobs/reclaim returns deleted: 0 without deleting).

Add POST /admin/blobs/reclaim, a protocol-only garbage collector for
blob-store artifacts no longer referenced by the graph. Enumeration runs
through BlobStore.scan() and deletion through the fenced
BlobStore.delete(uri, if_unmodified=ref) compare-and-delete -- no filesystem
path, glob, or os.unlink, and it never reaches the queue / identity / lease
stores or graph data.

Safety gates: a graph-wide reference scan over the blob-carrier allowlist, a
not-live / durable is_fully_drained session gate, a hard min_age_minutes floor
(>= 15), a destructive-apply single-flight (409 on overlap), a required
max_delete blast-radius cap, and dry_run=true by default. One structured audit
line per delete records only the ci-blob:// URI, never blob contents.

Fold in the blob-carrier allowlist (BLOB_REF_CARRIER_PROPERTIES in
blob_processor), reclaim's only consumer: the single source of truth for which
graph properties may carry a ci-blob:// reference, validated at import and
enforced at the mint site so an unregistered carrier fails loud instead of
becoming a silent reclaim-GC hole. The reference-scan Cypher is generated from
this tuple, so the two can never drift.

Version 7.4.0.

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <amplifier@microsoft.com>
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