Skip to content
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

Use ClassValue for caching #370

Merged
merged 6 commits into from Jun 27, 2022
Merged

Use ClassValue for caching #370

merged 6 commits into from Jun 27, 2022

Conversation

jglick
Copy link
Member

@jglick jglick commented Jun 16, 2022

Generally a good idea for avoiding memory leaks, though that may not be a real issue in Jenkins since the ClassLoaders involved are those of plugins, which would never be collected during the JVM session anyway.

Motivated by a CloudBees CI thread dump showing a large number of threads blocked like this:

"Handling HEAD /jenkins/instance-identity/ from … : Jetty (winstone)-…" …
    - waiting to lock <…> (a java.util.HashMap)
      owned by "Handling GET /jenkins/job/someItem/configure from … : Jetty (winstone)-… SomeStuff/configure.jelly" …
    at org.kohsuke.stapler.WebApp.getMetaClass(WebApp.java:227)
    at org.kohsuke.stapler.WebApp.getMetaClass(WebApp.java:244)
    at org.kohsuke.stapler.Stapler.tryInvoke(Stapler.java:762)
    at org.kohsuke.stapler.Stapler.invoke(Stapler.java:898)
    at org.kohsuke.stapler.Stapler.invoke(Stapler.java:694)
    at org.kohsuke.stapler.Stapler.service(Stapler.java:240)
    at …

all of them blocked by one HTTP handler thread

"Handling GET /jenkins/job/someItem/configure from … : Jetty (winstone)-… SomeStuff/configure.jelly" …
    - waiting to lock <…> (a hudson.ClassicPluginStrategy$AntClassLoader2)
      owned by "Computer.threadPoolForRemoting [#…]" …
    at java.lang.Class.forName0(Native Method)
    at …
    at java.lang.reflect.Method.getParameterAnnotations(Method.java:639)
    at org.kohsuke.stapler.Function$InstanceFunction.getParameterAnnotations(Function.java:423)
    at jenkins.security.stapler.DoActionFilter.keep(DoActionFilter.java:97)
    at jenkins.security.stapler.TypedFilter.isRoutableMethod(TypedFilter.java:131)
    at jenkins.security.stapler.TypedFilter.isSpecificClassStaplerRelevant(TypedFilter.java:98)
    at jenkins.security.stapler.TypedFilter.isStaplerRelevant(TypedFilter.java:65)
    at jenkins.security.stapler.TypedFilter.isStaplerRelevantCached(TypedFilter.java:57)
    at jenkins.security.stapler.TypedFilter.isClassAcceptable(TypedFilter.java:50)
    at jenkins.security.stapler.TypedFilter.keep(TypedFilter.java:267)
    at org.kohsuke.stapler.FunctionList.filter(FunctionList.java:48)
    at org.kohsuke.stapler.MetaClass.buildDispatchers(MetaClass.java:192)
    at org.kohsuke.stapler.MetaClass.<init>(MetaClass.java:98)
    at org.kohsuke.stapler.WebApp.getMetaClass(WebApp.java:230)
    at org.kohsuke.stapler.jelly.groovy.GroovyFacet.createRequestDispatcher(GroovyFacet.java:71)
    at org.kohsuke.stapler.RequestImpl.getView(RequestImpl.java:269)
    at org.kohsuke.stapler.RequestImpl.getView(RequestImpl.java:264)
    at hudson.model.Descriptor.getHelpFile(Descriptor.java:756)
    at hudson.model.Descriptor.getHelpFile(Descriptor.java:738)
    at …
    at org.apache.commons.jexl.ExpressionImpl.evaluate(ExpressionImpl.java:80)
    at hudson.ExpressionFactory2$JexlExpression.evaluate(ExpressionFactory2.java:74)
    at org.apache.commons.jelly.tags.core.CoreTagLibrary$3.run(CoreTagLibrary.java:134)
    at org.apache.commons.jelly.tags.core.CoreTagLibrary$1.run(CoreTagLibrary.java:98)
    at org.apache.commons.jelly.impl.ScriptBlock.run(ScriptBlock.java:95)
    at org.apache.commons.jelly.tags.core.CoreTagLibrary$2.run(CoreTagLibrary.java:105)
    at org.kohsuke.stapler.jelly.CallTagLibScript.run(CallTagLibScript.java:120)
    at org.apache.commons.jelly.impl.ScriptBlock.run(ScriptBlock.java:95)
    at org.apache.commons.jelly.tags.core.CoreTagLibrary$2.run(CoreTagLibrary.java:105)
    at org.kohsuke.stapler.jelly.JellyViewScript.run(JellyViewScript.java:95)
    at org.kohsuke.stapler.jelly.IncludeTag.doTag(IncludeTag.java:171)
    at org.apache.commons.jelly.impl.TagScript.run(TagScript.java:269)
    at …
    at org.kohsuke.stapler.Facet$1.dispatch(Facet.java:240)
    at org.kohsuke.stapler.Stapler.tryInvoke(Stapler.java:766)
    at org.kohsuke.stapler.Stapler.invoke(Stapler.java:898)
    at org.kohsuke.stapler.MetaClass$4.doDispatch(MetaClass.java:281)
    at org.kohsuke.stapler.NameBasedDispatcher.dispatch(NameBasedDispatcher.java:58)
    at org.kohsuke.stapler.Stapler.tryInvoke(Stapler.java:766)
    at org.kohsuke.stapler.Stapler.invoke(Stapler.java:898)
    at org.kohsuke.stapler.MetaClass$4.doDispatch(MetaClass.java:281)
    at org.kohsuke.stapler.NameBasedDispatcher.dispatch(NameBasedDispatcher.java:58)
    at org.kohsuke.stapler.Stapler.tryInvoke(Stapler.java:766)
    at org.kohsuke.stapler.Stapler.invoke(Stapler.java:898)
    at org.kohsuke.stapler.Stapler.invoke(Stapler.java:694)
    at org.kohsuke.stapler.Stapler.service(Stapler.java:240)
    at …

While a contributing factor was the Computer.threadPoolForRemoting thread (not shown), blocked in class loading predating paralellism (introduced I think in jenkinsci/jenkins#5698), this seems silly because some of the rendered threads are trying to load unrelated classes: WebApp.classMap was a bottleneck.

@jglick jglick added the bug label Jun 16, 2022
Copy link
Member

@timja timja left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 should probably run core tests first?

core/src/main/java/org/kohsuke/stapler/WebApp.java Outdated Show resolved Hide resolved
core/src/main/java/org/kohsuke/stapler/TearOffSupport.java Outdated Show resolved Hide resolved
Comment on lines +28 to +30
/**
* Like {@link ClassValue} but for a whole {@link ClassLoader}.
*/
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very creative!

@@ -90,7 +75,22 @@ static Object handle(StaplerRequest request, Annotation[] annotations, String pa
return null; // probably we should report an error
}

private static final ConcurrentMap<Class<? extends Annotation>,AnnotationHandler> HANDLERS = new ConcurrentHashMap<>();
private static final ClassValue<AnnotationHandler> HANDLERS = new ClassValue<AnnotationHandler>() {
@SuppressFBWarnings(value = "THROWS_METHOD_THROWS_RUNTIMEEXCEPTION", justification = "shut up")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My sentiment exactly.

@jglick
Copy link
Member Author

jglick commented Jun 16, 2022

run core tests

Probably. I ran jenkins.security.stapler.**.*Test successfully.

@jglick
Copy link
Member Author

jglick commented Jun 24, 2022

run core tests first

Or just YOLO-release; at worst we amend some problem or revert altogether and cut another release, if a DB PR turns up issues.

IIUC this cannot be tested directly against current Jenkins trunk because as of #373 it would fail pending jenkinsci/jenkins#6083.

@basil
Copy link
Member

basil commented Jun 24, 2022

Well for a few more hours anyway. I am planning to merge jenkinsci/jenkins#6083 today, just need to write a PR description. You know how it goes, writing the code is always the easy part, writing the docs always the hard part.

@basil
Copy link
Member

basil commented Jun 24, 2022

I just merged it so we should be good to go for testing this change now.

@jglick
Copy link
Member Author

jglick commented Jun 27, 2022

jenkinsci/jenkins#6693 passed.

@jglick jglick merged commit 93a11d2 into jenkinsci:master Jun 27, 2022
@jglick jglick deleted the ClassValue branch June 27, 2022 12:56
@basil
Copy link
Member

basil commented Aug 23, 2022

Or just YOLO-release; at worst we amend some problem or revert altogether and cut another release, if a DB PR turns up issues.

Issues have turned up indeed: jenkinsci/ec2-plugin#771

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants