Improve Queue.maintain performance by introducing cache for Util.isOverridden#26797
Conversation
There was a problem hiding this comment.
Pull request overview
This pull request aims to reduce Queue.maintain contention by caching Util.isOverridden results (avoiding repeated reflective lookups), and adds small APIs to observe and clear that cache.
Changes:
- Add an
isOverriddenresult cache inhudson.Utiland routeisOverriddenthrough it. - Add cache observability/maintenance methods (
isOverriddenCacheSize,clearIsOverriddenCache). - Add JUnit tests covering cache hit/miss behavior and cache keying.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| core/src/main/java/hudson/Util.java | Introduces the isOverridden cache plus cache size/clear methods. |
| core/src/test/java/hudson/util/IsOverriddenTest.java | Adds unit tests validating caching behavior and cache key composition. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // Keyed by (base, derived, methodName, paramTypes). Derived is held weakly so that plugin | ||
| // classloaders remain GC-eligible after unload. Results are stable for the lifetime of a | ||
| // classloader, so no invalidation is needed. | ||
| private static final ConcurrentHashMap<IsOverriddenCacheKey, Boolean> IS_OVERRIDDEN_CACHE = | ||
| new ConcurrentHashMap<>(); | ||
|
|
||
| private record IsOverriddenCacheKey( | ||
| Class<?> base, | ||
| WeakReference<Class<?>> derivedRef, | ||
| String methodName, | ||
| List<Class<?>> types) { | ||
|
|
||
| @Override | ||
| public boolean equals(Object o) { | ||
| if (!(o instanceof IsOverriddenCacheKey other)) return false; | ||
| return base == other.base | ||
| && derivedRef.get() == other.derivedRef.get() | ||
| && methodName.equals(other.methodName) | ||
| && types.equals(other.types); | ||
| } | ||
|
|
||
| @Override | ||
| public int hashCode() { | ||
| // Identity hash matches the identity comparison in equals. | ||
| return Objects.hash(base, System.identityHashCode(derivedRef.get()), methodName, types); | ||
| } |
There was a problem hiding this comment.
if/ once this is merged it should be possible to use caffeine if that is helpful: #26600
There was a problem hiding this comment.
Thanks for the review!
I can make that change, or a periodic task (hourly?) to call clear on the cache. Let me know if either are desired.
I wasn't too concerned without having expiry because it's very rare for me to unload a plugin without restarting Jenkins. I'm sure you'll have a better idea of how common this is across users of Jenkins, so happy to defer to you.
There was a problem hiding this comment.
tbh I don't think you can unload a plugin. May not be necessary
timja
left a comment
There was a problem hiding this comment.
Seems fine.
Did you notice any improvement in testing?
|
@timja I'm seeing a 96% reduction with the cache in a JMH Benchmark I ran on my laptop (3 forks, 5 warmup iterations, 10 measured iterations). I tried to create the conditions I saw issues with on the controller - about 1000 builds in the queue for
|
|
Is this the sort of change we might consider for a LTS backport? |
|
possibly but its not likely to make the next LTS patch version and as long as its in soon-ish it'll be in the next LTS baseline |
MarkEWaite
left a comment
There was a problem hiding this comment.
This PR is now ready for merge. We will merge it after approximately 24 hours if there is no negative feedback. Please see the merge process documentation for more information about the merge process.
/label ready-for-merge

Fixes #26796
Adds a method to check the size so cache monitoring can be easily wired into observability tools. Also adds a method to clear cache so it could be called from Jenkins script console if necessary. Happy to add a feature flag or make other changes if desired.
Testing done
Automated tests added and
mvn verifypassed.Screenshots (UI changes only)
N/A
Before
N/A
After
N/A
Proposed changelog entries
Util.is Overriddento improveQueue.maintainperformance.Proposed changelog category
/label internal
Proposed upgrade guidelines
N/A
Submitter checklist
@Restrictedor have@since TODOJavadocs, as appropriate.@Deprecated(since = "TODO")or@Deprecated(forRemoval = true, since = "TODO"), if applicable.evalto ease future introduction of Content Security Policy (CSP) directives (see documentation).Desired reviewers
@timja for being the initial reviewer on a similar change for this setup in #11032
Before the changes are marked as
ready-for-merge:Maintainer checklist
upgrade-guide-neededlabel is set and there is a Proposed upgrade guidelines section in the pull request title (see example).lts-candidateto be considered.