From eaf91000cb27768ba01f6b0ccbefcf27677324af Mon Sep 17 00:00:00 2001 From: Jesse Glick Date: Wed, 14 Jun 2023 03:31:28 -0400 Subject: [PATCH] `TransientActionFactory` cache simplification (#8048) * `TransientActionFactory` cache simplification * Fixing mocks in `HistoryPageFilterTest` --- .../jenkins/model/TransientActionFactory.java | 88 +++++++++---------- .../widgets/HistoryPageFilterTest.java | 24 +++++ 2 files changed, 64 insertions(+), 48 deletions(-) diff --git a/core/src/main/java/jenkins/model/TransientActionFactory.java b/core/src/main/java/jenkins/model/TransientActionFactory.java index 73b211751c..6eb1ed5269 100644 --- a/core/src/main/java/jenkins/model/TransientActionFactory.java +++ b/core/src/main/java/jenkins/model/TransientActionFactory.java @@ -24,10 +24,8 @@ package jenkins.model; -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.CacheLoader; -import com.google.common.cache.LoadingCache; import edu.umd.cs.findbugs.annotations.NonNull; +import hudson.Extension; import hudson.ExtensionList; import hudson.ExtensionListListener; import hudson.ExtensionPoint; @@ -80,59 +78,53 @@ public abstract class TransientActionFactory implements ExtensionPoint { */ public abstract @NonNull Collection createFor(@NonNull T target); - /** @see no pairs/tuples in Java */ - private static class CacheKey { - private final Class type; - private final Class actionType; + @Restricted(NoExternalUse.class) + @Extension + public static final class Cache extends ExtensionListListener { - CacheKey(Class type, Class actionType) { - this.type = type; - this.actionType = actionType; - } + @SuppressWarnings("rawtypes") + private ExtensionList allFactories; - @Override - public boolean equals(Object obj) { - return obj instanceof CacheKey && type == ((CacheKey) obj).type && actionType == ((CacheKey) obj).actionType; - } + private ClassValue>>> cache; - @Override - public int hashCode() { - return type.hashCode() ^ actionType.hashCode(); - } - } - - @SuppressWarnings("rawtypes") - private static final LoadingCache, LoadingCache>>> cache = - CacheBuilder.newBuilder().weakKeys().build(new CacheLoader<>() { - @Override - public LoadingCache>> load(final ExtensionList allFactories) throws Exception { - final LoadingCache>> perJenkinsCache = - CacheBuilder.newBuilder().build(new CacheLoader<>() { - @Override - public List> load(CacheKey key) throws Exception { - List> factories = new ArrayList<>(); - for (TransientActionFactory taf : allFactories) { - Class actionType = taf.actionType(); - if (taf.type().isAssignableFrom(key.type) && (key.actionType.isAssignableFrom(actionType) || actionType.isAssignableFrom(key.actionType))) { - factories.add(taf); - } + private synchronized ClassValue>>> cache() { + if (allFactories == null) { + allFactories = ExtensionList.lookup(TransientActionFactory.class); + allFactories.addListener(this); + } + if (cache == null) { + cache = new ClassValue<>() { + @Override + protected ClassValue>> computeValue(Class type) { + return new ClassValue<>() { + @Override + protected List> computeValue(Class actionType) { + List> factories = new ArrayList<>(); + for (TransientActionFactory taf : allFactories) { + if (taf.type().isAssignableFrom(type) && (actionType.isAssignableFrom(taf.actionType()) || taf.actionType().isAssignableFrom(actionType))) { + factories.add(taf); + } + } + return factories; + } + }; } - return factories; - } - }); - allFactories.addListener(new ExtensionListListener() { - @Override - public void onChange() { - perJenkinsCache.invalidateAll(); - } - }); - return perJenkinsCache; + }; + } + return cache; } - }); + + + @Override + public synchronized void onChange() { + cache = null; + } + + } @Restricted(NoExternalUse.class) // pending a need for it outside Actionable public static Iterable> factoriesFor(Class type, Class actionType) { - return cache.getUnchecked(ExtensionList.lookup(TransientActionFactory.class)).getUnchecked(new CacheKey(type, actionType)); + return ExtensionList.lookupSingleton(Cache.class).cache().get(type).get(actionType); } } diff --git a/core/src/test/java/jenkins/widgets/HistoryPageFilterTest.java b/core/src/test/java/jenkins/widgets/HistoryPageFilterTest.java index 3ce79bf426..34f7800d33 100644 --- a/core/src/test/java/jenkins/widgets/HistoryPageFilterTest.java +++ b/core/src/test/java/jenkins/widgets/HistoryPageFilterTest.java @@ -24,6 +24,7 @@ package jenkins.widgets; +import hudson.model.Action; import hudson.model.Build; import hudson.model.FreeStyleBuild; import hudson.model.FreeStyleProject; @@ -446,6 +447,18 @@ public class HistoryPageFilterTest { public int getNumber() { return (int) queueId; } + + @SuppressWarnings("deprecation") // avoid TransientActionFactory + @Override + public T getAction(Class type) { + for (Action a : getActions()) { + if (type.isInstance(a)) { + return type.cast(a); + } + } + return null; + } + } // A version of MockRun that will throw an exception if getQueueId or getNumber is called @@ -510,6 +523,17 @@ public class HistoryPageFilterTest { return this; } + @SuppressWarnings("deprecation") // avoid TransientActionFactory + @Override + public T getAction(Class type) { + for (Action a : getActions()) { + if (type.isInstance(a)) { + return type.cast(a); + } + } + return null; + } + private StringParameterValue createSensitiveStringParameterValue(final String paramName, final String paramValue) { return new StringParameterValue(paramName, paramValue) { @Override