Skip to content

lru: slab-elements instead of grow - #23557

Closed
AskAlexSharov wants to merge 1 commit into
mainfrom
alex/lru_slab_elements_37
Closed

lru: slab-elements instead of grow#23557
AskAlexSharov wants to merge 1 commit into
mainfrom
alex/lru_slab_elements_37

Conversation

@AskAlexSharov

Copy link
Copy Markdown
Collaborator

freelru sizes its element array from capacity at construction, so a cache either pre-commits its whole ceiling or gets copied into a bigger table as it fills. That copy is what costs fenced=194.8ms at 1M entries on n5, with a 4,194,304-entry step still ahead of it.

It does not have to be that way. Element positions are dense and self-relative — pos := lru.len, and every stored index (buckets[b], nextBucket, prevBucket, next, prev, head) is an offset into the same array. So the array need not be contiguous: hold it as fixed 8192-entry slabs (~917 KB) appended on demand.

  • Residency follows what is stored, not what is configured. An empty cache holds zero slabs.
  • Capacity never needs a rehash, so there is no grow path at all: maybeGrow, the all-stripe fence, curCap and the generation swap are gone.
  • Only the bucket index is sized up front, and it is 4 B per slot.

execution/cache/slablru is freelru's single LRU vendored (LGPL/Apache headers kept) with elements []element replaced by slabs [][]element plus an elem(pos) accessor and reserve(pos). Upstream's own test suite is vendored with it and passes unchanged — that is the correctness argument. TestSlabsGrowOnDemand pins the new property: zero slabs empty, one at 8192 entries, two at 8193, and every key still addressable across the boundary.

Two tests are deleted rather than adapted, because the code they guard no longer exists: TestGenericCache_PutIfAbsentDefersAcrossGrow and TestGenericCache_GrowMigrationLossless both pin hazards of the jump-grow generation swap. There is no migration and no swap on growth any more — the only remaining swap is Clear, which is a different, fenced path.

Known gap for review: envelope accounting still charges at construction as before and does not yet follow slab allocation. It should charge buckets up front and a slab as each is appended.

Alternative to #23546 and #23553, which keep the copy and make it cheaper. Independent of #23552.

@AskAlexSharov
AskAlexSharov force-pushed the alex/lru_slab_elements_37 branch 10 times, most recently from f44f71a to 9ebefb0 Compare August 25, 2026 09:38
freelru sizes the element array from capacity at construction, so a cache
either pre-commits its whole ceiling or has to be copied into a bigger table
as it fills -- 195ms fenced at 1M entries, and the ladder ends with a
4.19M-entry step. Element positions are dense and self-relative, so the array
does not have to be contiguous: hold it as 8192-entry slabs appended on
demand. Residency then follows what is stored, and capacity never needs a
rehash. Only the bucket index, 4B per slot, is sized up front.
@AskAlexSharov
AskAlexSharov force-pushed the alex/lru_slab_elements_37 branch from 9ebefb0 to e9a4214 Compare August 25, 2026 10:56
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