Problem
GET /projects/{name}/summary returns quota_usage.used which is maintained as a running counter in the database rather than computed from actual blob storage. This counter can drift from reality when:
- An upload fails mid-way
- A transaction rollback does not fully complete
The counter only self-corrects when garbage collection (GC) or an explicit delete operation runs. During the drift window, quota checks are inaccurate.
Current behavior
quota_usage.used is a mutable running counter. It increments/decrements on blob operations but has no reconciliation path for failed or partially rolled back transactions.
Expected behavior
Quota usage reflects actual bytes stored in project_blob at all times, with no drift.
Proposed fix
Harbor already has CalculateTotalSizeByProject internally, which does a live SUM from project_blob. Rather than adding a new endpoint as a workaround, the quota check path should be reworked to eliminate the running counter entirely either by:
- Live aggregate: Replace
quota_usage.used reads with a query against project_blob backed by an appropriate index.
- Update an indexed aggregate transactionally on every blob insert/delete, eliminating async drift.
Either approach removes the need for GC to act as a correctness mechanism for quota.
Notes
CalculateTotalSizeByProject exists in the codebase but is not currently exposed via any public API. A GET /projects/{name}/storage endpoint was considered as a short-term workaround but a proper fix to the counter is preferred
- This was discussed in the Harbor community Slack - https://cloud-native.slack.com/archives/CC1E09J6S/p1783454715724819
Problem
GET /projects/{name}/summary returns quota_usage.usedwhich is maintained as a running counter in the database rather than computed from actual blob storage. This counter can drift from reality when:The counter only self-corrects when garbage collection (GC) or an explicit delete operation runs. During the drift window, quota checks are inaccurate.
Current behavior
quota_usage.usedis a mutable running counter. It increments/decrements on blob operations but has no reconciliation path for failed or partially rolled back transactions.Expected behavior
Quota usage reflects actual bytes stored in
project_blobat all times, with no drift.Proposed fix
Harbor already has
CalculateTotalSizeByProjectinternally, which does a liveSUMfromproject_blob. Rather than adding a new endpoint as a workaround, the quota check path should be reworked to eliminate the running counter entirely either by:quota_usage.usedreads with a query againstproject_blobbacked by an appropriate index.Either approach removes the need for GC to act as a correctness mechanism for quota.
Notes
CalculateTotalSizeByProjectexists in the codebase but is not currently exposed via any public API. AGET /projects/{name}/storageendpoint was considered as a short-term workaround but a proper fix to the counter is preferred