Files
Rajiv Harlalka 609269e0ae Fix GetCharge on uncharged standalone LRU entries
Summary:
X-link: https://github.com/facebook/rocksdb/pull/15501

Why the change is required:
`Cache::CreateStandalone` documents that with `strict_capacity_limit` and no
room, `allow_uncharged=true` creates the entry anyway with `GetCharge() == 0`.
The secondary cache adapter relies on this whenever it promotes an entry into
a full strict primary cache. Under `kFullChargeCacheMetadata` (the default),
such entries violated the public API contract.

Previous behavior:
`LRUCacheShard::CreateStandalone` sets `total_charge = 0` for an uncharged
entry, but `LRUHandle::GetCharge` unconditionally subtracted the metadata
charge. Debug builds aborted on `assert(total_charge >= meta_charge)`;
release builds reported enormous per-handle charges from unsigned underflow,
corrupting block-cache byte statistics through `GetUsage(handle)` in
`UpdateCacheHitMetrics`. The trigger requires an LRU cache with
`strict_capacity_limit`, full metadata charging, pinned entries preventing
sufficient eviction, and `allow_uncharged=true`. `kDontChargeCacheMetadata`
and HyperClockCache are unaffected.

New behavior:
Uncharged standalone handles report `GetCharge() == 0`, preventing the debug
assertion failure and incorrect release-build byte statistics.
`GetUsage(handle)` and `ApplyToHandle` also receive the correct charge. Total
cache usage accounting is unchanged: uncharged handles add no usage on
creation and subtract none on release.

Implementation:
`LRUHandle::GetCharge` returns zero for standalone handles with the named
zero-charge sentinel, retaining the existing assertion for other handles.
Added a release note and simplified the direct API regression test.
`FullCapacityTest` now exercises both metadata charge policies and verifies
zero per-handle usage when strict capacity forces secondary-cache promotion
to use an uncharged standalone handle. Its 700-byte values leave room for
metadata while ensuring two entries still exceed the 1024-byte capacity.

Safety, compatibility, and limitations:
Only the previously broken standalone, uncharged case changes its returned
charge. There are no API signature, ABI, or serialized-format changes.
The added check runs on every LRU `GetCharge` call, for every handle,
including block-cache hits through `UpdateCacheHitMetrics` and
`GetUsage(handle)`. Expected overhead is negligible because `im_flags` is
stored near `total_charge` and the branch is predictable; this is an
assessment of the code, with no performance benchmark performed.

Reviewed By: xingbowang

Differential Revision: D126972213

fbshipit-source-id: 595d8771b0e57f20c12314e00c2aa2d7d2965a34
2026-10-29 12:47:48 -07:00
..
2026-02-13 11:56:22 -08:00
2025-10-03 14:28:37 -07:00