Use LruCache for the other three least-recently-used caches - #6240
Use LruCache for the other three least-recently-used caches#6240SanderMuller wants to merge 2 commits into
Conversation
phpstan#5928 introduced LruCache for the parser's file-contents memo. Three more caches were doing the same bookkeeping by hand, so they now use it as well: - PhpClassReflectionExtension's shared member-cache order, where set() returning the evicted keys is what lets the four member maps drop the same key - FileTypeMapper's name-scope map memo, whose manual entry counter count() replaces - UsefulTypeAliasResolver's resolved local type aliases FileTypeMapper's cache treated a configured maximum of 0 as "keep one entry" rather than "no limit" as the others do, because its eviction loop ran before the insertion. That is preserved as-is; normalising it would change behaviour for anyone who set the parameter to 0. FileTypeMapper's resolvedPhpDocBlockCache is deliberately left alone: it does not touch entries on a hit, so it evicts in insertion order rather than by use, and moving it to LruCache would change its eviction policy rather than just its shape. Behaviour unchanged on an identical analysis: same errors reported, and the same cache footprint - 1168 name-scope map misses, 2 local type alias misses and 910 member-cache evictions before and after. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Please provide time/memory measurements. This is only worth it if it leads to improvements. |
|
Of course the LruCache refacoring is nice but should be separste from introducing the cache to new places. |
The four limits are only read where the LruCache is constructed, so holding them as promoted properties keeps per-instance state nobody reads and suggests the classes consult them later. Plain constructor parameters instead. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Double-checked this before it gets reviewed, and it earned two additions. Eviction is now actually exercised. The footprint numbers in the description came from a run with the shipped limits, where the type-alias cache only ever held two entries - so its eviction path was never touched. Re-ran the differential with the limits turned down, and with them at
The second row is the one that matters for Second commit: the limits are no longer properties. All four - including Also checked and found nothing: no reference to the replaced properties survives anywhere in CI: the three reds are the two Symplify integration jobs (composer 404 on the |
|
To be clear on the intent: this adds no caching and was not aimed at performance. It re-uses the Measurements anyway, base
The time deltas sit inside spreads several times their size, so read it as unchanged - no gain, no regression. The hit/miss footprint is identical too (1168 name-scope map misses, 910 member-cache evictions on both sides), which is the point: same caches, same behaviour, less code. If that cleanup is not worth carrying the abstraction, close it and I will not argue - the class stays in from #5928 either way. Two side notes. The second commit (the limits stop being properties, since they are only read where the cache is constructed) is a separate concern - happy to split it out. And |
Follow-up to #5928, which introduced
LruCachefor the parser's file-contents memo. staabm asked in #5928 (comment) whether other places could use it - three could, and here they are.PhpClassReflectionExtension::touchMemberCacheKey()set()returning the evicted keys is what lets all four drop the same keyFileTypeMapper::$memoryCache$memoryCacheCount, whichcount()replacesUsefulTypeAliasResolver::$resolvedLocalTypeAliasesTwo deliberate non-changes:
FileTypeMapper::$resolvedPhpDocBlockCacheis left alone. It does not touch entries on a hit, so despite sitting next to an LRU it evicts in insertion order. Moving it would change its eviction policy, which wants measuring on its own rather than riding along in a refactor.nameScopeMapMemoryCacheCountMax: 0keeps its odd meaning. In the other three caches 0 means "no limit"; here the eviction loop ran before the insertion, so 0 emptied the cache and put a single entry back - a one-entry cache. The constructor maps it tonew LruCache(1)so nobody who set that parameter to 0 gets an unbounded cache instead. Happy to normalise it to "no limit" in a separate PR if you would rather the four behaved alike; it is a behaviour change, so I did not fold it in.Verification:
src/Rules+src/Type/Php, sorted diff clean).No new tests: these are behaviour-preserving conversions of existing caches, and
LruCacheitself hasLruCacheTestfrom #5928.