Skip to content
Permalink
Browse files

[FIXED JENKINS-33971] ReverseBuildTrigger.upstream2Trigger was not be…

…ing reliably calculated during Jenkins startup.

(cherry picked from commit 1618270)
  • Loading branch information
jglick authored and olivergondza committed Apr 25, 2016
1 parent 8953269 commit 28bc2ba67a29f879ee7b840b46f383281dd1fe8a
Showing with 48 additions and 26 deletions.
  1. +48 −26 core/src/main/java/jenkins/triggers/ReverseBuildTrigger.java
@@ -25,6 +25,7 @@
package jenkins.triggers;

import hudson.Extension;
import hudson.ExtensionList;
import hudson.Util;
import hudson.console.ModelHyperlinkNote;
import hudson.model.AbstractBuild;
@@ -86,7 +87,6 @@
public final class ReverseBuildTrigger extends Trigger<Job> implements DependencyDeclarer {

private static final Logger LOGGER = Logger.getLogger(ReverseBuildTrigger.class.getName());
private static final Map<Job,Collection<ReverseBuildTrigger>> upstream2Trigger = new WeakHashMap<>();

private String upstreamProjects;
private final Result threshold;
@@ -149,34 +149,12 @@ private boolean shouldTrigger(Run upstreamBuild, TaskListener listener) {

@Override public void start(@Nonnull Job project, boolean newInstance) {
super.start(project, newInstance);
SecurityContext orig = ACL.impersonate(ACL.SYSTEM);
try {
for (Job upstream : Items.fromNameList(project.getParent(), upstreamProjects, Job.class)) {
if (upstream instanceof AbstractProject && project instanceof AbstractProject) {
continue; // handled specially
}
synchronized (upstream2Trigger) {
Collection<ReverseBuildTrigger> triggers = upstream2Trigger.get(upstream);
if (triggers == null) {
triggers = new LinkedList<>();
upstream2Trigger.put(upstream, triggers);
}
triggers.remove(this);
triggers.add(this);
}
}
} finally {
SecurityContextHolder.setContext(orig);
}
RunListenerImpl.get().invalidateCache();
}

@Override public void stop() {
super.stop();
synchronized (upstream2Trigger) {
for (Collection<ReverseBuildTrigger> triggers : upstream2Trigger.values()) {
triggers.remove(this);
}
}
RunListenerImpl.get().invalidateCache();
}

@Extension public static final class DescriptorImpl extends TriggerDescriptor {
@@ -225,9 +203,53 @@ public FormValidation doCheckUpstreamProjects(@AncestorInPath Job project, @Quer
}

@Extension public static final class RunListenerImpl extends RunListener<Run> {

static RunListenerImpl get() {
return ExtensionList.lookup(RunListener.class).get(RunListenerImpl.class);
}

private Map<Job,Collection<ReverseBuildTrigger>> upstream2Trigger;

synchronized void invalidateCache() {
upstream2Trigger = null;
}

private Map<Job,Collection<ReverseBuildTrigger>> calculateCache() {
Map<Job,Collection<ReverseBuildTrigger>> result = new WeakHashMap<>();
SecurityContext orig = ACL.impersonate(ACL.SYSTEM);
for (Job<?, ?> downstream : Jenkins.getInstance().getAllItems(Job.class)) {
ReverseBuildTrigger trigger = ParameterizedJobMixIn.getTrigger(downstream, ReverseBuildTrigger.class);
if (trigger == null) {
continue;
}
try {
List<Job> upstreams = Items.fromNameList(downstream.getParent(), trigger.upstreamProjects, Job.class);
LOGGER.log(Level.FINE, "from {0} see upstreams {1}", new Object[] {downstream, upstreams});
for (Job upstream : upstreams) {
if (upstream instanceof AbstractProject && downstream instanceof AbstractProject) {
continue; // handled specially
}
Collection<ReverseBuildTrigger> triggers = result.get(upstream);
if (triggers == null) {
triggers = new LinkedList<>();
result.put(upstream, triggers);
}
triggers.remove(trigger);
triggers.add(trigger);
}
} finally {
SecurityContextHolder.setContext(orig);
}
}
return result;
}

@Override public void onCompleted(@Nonnull Run r, @Nonnull TaskListener listener) {
Collection<ReverseBuildTrigger> triggers;
synchronized (upstream2Trigger) {
synchronized (this) {
if (upstream2Trigger == null) {
upstream2Trigger = calculateCache();
}
Collection<ReverseBuildTrigger> _triggers = upstream2Trigger.get(r.getParent());
if (_triggers == null || _triggers.isEmpty()) {
return;

0 comments on commit 28bc2ba

Please sign in to comment.
You can’t perform that action at this time.