Skip to content

Chore: Extracted interface Cache from 'LRUCache' #130964

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 17 commits into
base: main
Choose a base branch
from

Conversation

mjmbischoff
Copy link
Contributor

@mjmbischoff mjmbischoff commented Jul 9, 2025

Chore: Extracting a Cache interface to allow exploring alternative implementations. Alternative implementations are outside the scope of this PR.

I know indirection is bad for performance, but the Cache/LRUCache already lists trade-offs, I expect things to get inlined, everything considered I don't think this will 'do us in'.

Along the way found some minor bugs and issues

  • Renamed Cache to LRUCache and extracted an interface and put under the old name to allow other implementations to be tested.
  • Found and fixed minor bug where we tested max weight against count() instead of weight
  • Found and fixed minor issue with possible long overflow.
  • Adjusted tests but made explicit the ones who rely on the LRUCache implementation to test if settings are applied correctly. While CacheBuilder#build() returns a Cache it still always returns the LRUCache implementation
  • renamed Cache.CacheStats to Cache.Stats and made it a record. Getters we're kept for now, should perhaps inline access in the future.
  • Updated the javadoc of the interface to provide enough guarantees for current usage while also lowering it to provide more flexibility for future alternative implementations
  • Notification of removal is documented in the javadoc and class is documented with regards to registering a RemovalListener and how the interface doesn't mandate how, how many and effects if registered listeners are modified after construction
  • Adding test to assert implementations of Cache follow the contract

NOTES (ramblings of the author, for context, can be ignored):

The wording of javadoc of the old Cache/LRUCache might have sounded 'overly scary/dangerous' leading to some interesting usage/interaction

As already pointed out in comments org.elasticsearch.xpack.core.security.support.CacheIteratorHelper, it's a little wonk. I'm also unsure if the extra protection is needed. Regardless the design of that class to leak the locks and not pull up interaction and fully decorate a cache a la Collections.unmodifiableXXX(XXX) is... 'not (personally) preferred'.

A computed weight is being tracked as long, which can overflow. Always calculating it on the fly or calculating it on the fly after detecting overflow is an option. Also wondering about thread safety as we're incrementing and something like an AtomicLong is needed. 'Best-effort' :-) Changing the LRUCache impl is out of scope of this PR.

TODO / Ponder on

  • We both have a forEach() to loop all entries and two iterators to loop over keys and values separately - should probably harmonize this using the same pattern for all 3? not changing LRUCache
  • the forEach locks the segment, iterators do not, neither provides a point-in-time view of the cache, not sure what the benefit of the guarantee of locking the segment does to the consumer, since which entry belongs to which segment is an internal detail so interaction has no guarantee of hitting any particular segment. If one safely (correctly?) assumes the lowest common denominator it would provide the same guarantee, with the other just having the downside of potentially deadlocking. not changing LRUCache
  • weight() perhaps move it to stats? weight doesn't have a fixed unit.

…nder the old name to allow other implementations to be tested.

- Found and fixed minor bug where we tested max weight against count() instead of weight
- Found and fixed minor issue with possible long overflow.
- Adjusted tests but made explicit the ones who rely on the `LRUCache` implementation to test if settings are applied correctly.
While CacheBuilder#build() returns a `Cache` it still always returns the `LRUCache` implementation
@elasticsearchmachine elasticsearchmachine added v9.2.0 external-contributor Pull request authored by a developer outside the Elasticsearch team labels Jul 10, 2025
@mjmbischoff mjmbischoff marked this pull request as ready for review July 14, 2025 14:24
@elasticsearchmachine elasticsearchmachine added the needs:triage Requires assignment of a team area label label Jul 14, 2025
@mjmbischoff mjmbischoff self-assigned this Jul 15, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
external-contributor Pull request authored by a developer outside the Elasticsearch team needs:triage Requires assignment of a team area label v9.2.0
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants