Follow-up to #22869 (see its review discussion; #22466 introduced the pattern for GenericCache).
Current state
The put-stripe fencing discipline — writers stamp the coherence epoch under a per-key stripe, while Clear holds every stripe across the storage purge and the coherence Reset — is implemented three times:
GenericCache (execution/cache/generic_cache.go): putStripes [putStripeCount]sync.Mutex plus inline lock-all/unlock-all loops in Clear and maybeGrow
CodeCache (execution/cache/code_cache.go): putStripes [256]sync.Mutex plus lockPutStripes/unlockPutStripes (ordered pair) and lockAllPutStripes/unlockAllPutStripes
BranchCache (execution/commitment/branch_cache.go): putStripes [256]sync.Mutex plus putStripe(prefix) and lockAllPutStripes/unlockAllPutStripes
All three use 256 stripes. The copies also differ cosmetically: CodeCache/BranchCache unlock in reverse order, GenericCache unlocks forward (the order is immaterial).
Proposal
Extract one small shared type, e.g. coherence.Stripes:
type Stripes [256]sync.Mutex
func (s *Stripes) Of(i uint8) *sync.Mutex
func (s *Stripes) LockPair(a, b uint8) // ordered, dedups a == b
func (s *Stripes) UnlockPair(a, b uint8)
func (s *Stripes) LockAll()
func (s *Stripes) UnlockAll()
The stripes exist purely to make stamped publications atomic with Clear, so the coherence package is a natural home. If coherence should stay a pure atomic-state leaf, a sibling leaf package works too.
Scope
Mechanical refactor, no behavior change. Do it after #22869 merges (the BranchCache stripes only exist on that branch). Safety net: the existing concurrency regressions (TestGenericCache_ClearRacingPut_EpochAlias, TestCodeCache_ClearFencesStartedPut, TestBranchCache_ClearFencesStartedPut/PinEntry, and the size-drift tests).
Follow-up to #22869 (see its review discussion; #22466 introduced the pattern for
GenericCache).Current state
The put-stripe fencing discipline — writers stamp the coherence epoch under a per-key stripe, while
Clearholds every stripe across the storage purge and the coherenceReset— is implemented three times:GenericCache(execution/cache/generic_cache.go):putStripes [putStripeCount]sync.Mutexplus inline lock-all/unlock-all loops inClearandmaybeGrowCodeCache(execution/cache/code_cache.go):putStripes [256]sync.MutexpluslockPutStripes/unlockPutStripes(ordered pair) andlockAllPutStripes/unlockAllPutStripesBranchCache(execution/commitment/branch_cache.go):putStripes [256]sync.MutexplusputStripe(prefix)andlockAllPutStripes/unlockAllPutStripesAll three use 256 stripes. The copies also differ cosmetically:
CodeCache/BranchCacheunlock in reverse order,GenericCacheunlocks forward (the order is immaterial).Proposal
Extract one small shared type, e.g.
coherence.Stripes:The stripes exist purely to make stamped publications atomic with
Clear, so thecoherencepackage is a natural home. Ifcoherenceshould stay a pure atomic-state leaf, a sibling leaf package works too.Scope
Mechanical refactor, no behavior change. Do it after #22869 merges (the
BranchCachestripes only exist on that branch). Safety net: the existing concurrency regressions (TestGenericCache_ClearRacingPut_EpochAlias,TestCodeCache_ClearFencesStartedPut,TestBranchCache_ClearFencesStartedPut/PinEntry, and the size-drift tests).