Skip to content

Commit

Permalink
Merge pull request #3428 from jglick/perf-JENKINS-51205
Browse files Browse the repository at this point in the history
[JENKINS-51205] Improve performance of /pluginManager/available service
  • Loading branch information
jglick committed May 10, 2018
2 parents d004eea + 3b61b96 commit 6bb85ec
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 23 deletions.
14 changes: 14 additions & 0 deletions core/src/main/java/hudson/PluginManager.java
Expand Up @@ -144,6 +144,7 @@
import java.net.JarURLConnection;
import java.net.URLConnection;
import java.util.ServiceLoader;
import java.util.function.Supplier;
import java.util.jar.JarEntry;

import static java.util.logging.Level.FINE;
Expand Down Expand Up @@ -1816,6 +1817,19 @@ public Map<String,VersionNumber> parseRequestedPlugins(InputStream configXml) th
return requestedPlugins;
}

@Restricted(DoNotUse.class) // table.jelly
public MetadataCache createCache() {
return new MetadataCache();
}

@Restricted(NoExternalUse.class) // table.jelly
public static final class MetadataCache {
private final Map<String, Object> data = new HashMap<>();
public <T> T of(String key, Class<T> type, Supplier<T> func) {
return type.cast(data.computeIfAbsent(key, _ignored -> func.get()));
}
}

/**
* {@link ClassLoader} that can see all plugins.
*/
Expand Down
52 changes: 31 additions & 21 deletions core/src/main/java/hudson/model/UpdateSite.java
Expand Up @@ -120,11 +120,6 @@ public class UpdateSite {
*/
private transient volatile long retryWindow;

/**
* lastModified time of the data file when it was last read.
*/
private transient long dataLastReadFromFile;

/**
* Latest data as read from the data file.
*/
Expand Down Expand Up @@ -226,6 +221,7 @@ private FormValidation updateData(String json, boolean signatureCheck)
LOGGER.info("Obtained the latest update center data file for UpdateSource " + id);
retryWindow = 0;
getDataFile().write(json);
data = new Data(o);
return FormValidation.ok();
}

Expand Down Expand Up @@ -309,23 +305,20 @@ public boolean isDue() {
public HttpResponse doInvalidateData() {
Jenkins.getInstance().checkPermission(Jenkins.ADMINISTER);
dataTimestamp = 0;
data = null;
return HttpResponses.ok();
}

/**
* Loads the update center data, if any and if modified since last read.
* Loads the update center data, if any.
*
* @return null if no data is available.
*/
public Data getData() {
TextFile df = getDataFile();
if (df.exists() && dataLastReadFromFile != df.file.lastModified()) {
if (data == null) {
JSONObject o = getJSONObject();
if (o!=null) {
if (o != null) {
data = new Data(o);
dataLastReadFromFile = df.file.lastModified();
} else {
data = null;
}
}
return data;
Expand Down Expand Up @@ -1094,10 +1087,19 @@ public VersionNumber getNeededDependenciesRequiredCore() {
}

public boolean isNeededDependenciesForNewerJenkins() {
for (Plugin p: getNeededDependencies()) {
if (p.isForNewerHudson() || p.isNeededDependenciesForNewerJenkins()) return true;
}
return false;
return isNeededDependenciesForNewerJenkins(new PluginManager.MetadataCache());
}

@Restricted(NoExternalUse.class) // table.jelly
public boolean isNeededDependenciesForNewerJenkins(PluginManager.MetadataCache cache) {
return cache.of("isNeededDependenciesForNewerJenkins:" + name, Boolean.class, () -> {
for (Plugin p : getNeededDependencies()) {
if (p.isForNewerHudson() || p.isNeededDependenciesForNewerJenkins()) {
return true;
}
}
return false;
});
}

/**
Expand All @@ -1109,11 +1111,19 @@ public boolean isNeededDependenciesForNewerJenkins() {
* specified, it'll return true.
*/
public boolean isNeededDependenciesCompatibleWithInstalledVersion() {
for (Plugin p: getNeededDependencies()) {
if (!p.isCompatibleWithInstalledVersion() || !p.isNeededDependenciesCompatibleWithInstalledVersion())
return false;
}
return true;
return isNeededDependenciesCompatibleWithInstalledVersion(new PluginManager.MetadataCache());
}

@Restricted(NoExternalUse.class) // table.jelly
public boolean isNeededDependenciesCompatibleWithInstalledVersion(PluginManager.MetadataCache cache) {
return cache.of("isNeededDependenciesCompatibleWithInstalledVersion:" + name, Boolean.class, () -> {
for (Plugin p : getNeededDependencies()) {
if (!p.isCompatibleWithInstalledVersion() || !p.isNeededDependenciesCompatibleWithInstalledVersion()) {
return false;
}
}
return true;
});
}

/**
Expand Down
5 changes: 3 additions & 2 deletions core/src/main/resources/hudson/PluginManager/table.jelly
Expand Up @@ -72,6 +72,7 @@ THE SOFTWARE.
<j:choose>
<j:when test="${!empty(list)}">
<j:set var="lastCat" value="" />
<j:set var="cache" value="${it.createCache()}"/>
<j:forEach var="p" items="${list}">
<j:if test="${!isUpdates}">
<j:set var="thisCat" value="${p.category}" />
Expand Down Expand Up @@ -105,10 +106,10 @@ THE SOFTWARE.
<j:if test="${p.isForNewerHudson()}">
<div class="compatWarning">${%coreWarning(p.requiredCore)}</div>
</j:if>
<j:if test="${!p.isNeededDependenciesCompatibleWithInstalledVersion()}">
<j:if test="${!p.isNeededDependenciesCompatibleWithInstalledVersion(cache)}">
<div class="compatWarning">${%depCompatWarning}</div>
</j:if>
<j:if test="${p.isNeededDependenciesForNewerJenkins()}">
<j:if test="${p.isNeededDependenciesForNewerJenkins(cache)}">
<div class="compatWarning">${%depCoreWarning(p.getNeededDependenciesRequiredCore().toString())}</div>
</j:if>
<j:if test="${p.hasWarnings()}">
Expand Down

0 comments on commit 6bb85ec

Please sign in to comment.