Skip to content
This repository has been archived by the owner on Dec 15, 2021. It is now read-only.

Commit

Permalink
Merge pull request #289 from jglick/deadlocks-JENKINS-31614
Browse files Browse the repository at this point in the history
[JENKINS-31614] Avoid acquiring the Queue lock while holding other locks
  • Loading branch information
jglick committed Jan 8, 2016
2 parents 1c87228 + c89a054 commit cb65b31
Show file tree
Hide file tree
Showing 6 changed files with 36 additions and 20 deletions.
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Only noting significant user changes, not internal code cleanups and minor bug f
## 1.13 (upcoming) ## 1.13 (upcoming)


* [JENKINS-26126](https://issues.jenkins-ci.org/browse/JENKINS-26126) (partial): introspect Workflow steps to generate static reference documentation (link from _Snippet Generator_). Planned to be used for IDE auto-completion as well. * [JENKINS-26126](https://issues.jenkins-ci.org/browse/JENKINS-26126) (partial): introspect Workflow steps to generate static reference documentation (link from _Snippet Generator_). Planned to be used for IDE auto-completion as well.
* [JENKINS-31614](https://issues.jenkins-ci.org/browse/JENKINS-31614): avoiding various deadlocks involving `Queue`.
* [JENKINS-31897](https://issues.jenkins-ci.org/browse/JENKINS-31897): parameters with default values may now be omitted from the `parameters` option to the `build` step. * [JENKINS-31897](https://issues.jenkins-ci.org/browse/JENKINS-31897): parameters with default values may now be omitted from the `parameters` option to the `build` step.
* [JENKINS-31909](https://issues.jenkins-ci.org/browse/JENKINS-31909): form validation warning about Groovy syntax errors was broken in 1.11. * [JENKINS-31909](https://issues.jenkins-ci.org/browse/JENKINS-31909): form validation warning about Groovy syntax errors was broken in 1.11.
* [JENKINS-31391](https://issues.jenkins-ci.org/browse/JENKINS-31391): pass `EXECUTOR_NUMBER` into `node {}`. * [JENKINS-31391](https://issues.jenkins-ci.org/browse/JENKINS-31391): pass `EXECUTOR_NUMBER` into `node {}`.
Expand Down
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ public abstract class Pickle implements Serializable {
/** /**
* Start preparing rehydration of this value, and when it's ready or fail, report that to the * Start preparing rehydration of this value, and when it's ready or fail, report that to the
* given call. * given call.
* An implementation should return quickly and avoid acquiring locks in this method itself (as opposed to the future).
*/ */
public abstract ListenableFuture<?> rehydrate(); public abstract ListenableFuture<?> rehydrate();


Expand Down
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -474,7 +474,11 @@ private String key() {
listener = new StreamBuildListener(new NullStream()); listener = new StreamBuildListener(new NullStream());
} }
completed = new AtomicBoolean(); completed = new AtomicBoolean();
Queue.getInstance().schedule(new AfterRestartTask(this), 0); Timer.get().submit(new Runnable() { // JENKINS-31614
@Override public void run() {
Queue.getInstance().schedule(new AfterRestartTask(WorkflowRun.this), 0);
}
});
} }
} }
checkouts(null); // only for diagnostics checkouts(null); // only for diagnostics
Expand Down
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
package org.jenkinsci.plugins.workflow.support.pickles; package org.jenkinsci.plugins.workflow.support.pickles;


import org.jenkinsci.plugins.workflow.pickles.Pickle; import org.jenkinsci.plugins.workflow.pickles.Pickle;
import org.jenkinsci.plugins.workflow.support.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import hudson.Extension; import hudson.Extension;
import hudson.model.Executor; import hudson.model.Executor;
Expand Down Expand Up @@ -62,17 +61,19 @@ private ExecutorPickle(Executor executor) {
} }


@Override public ListenableFuture<Executor> rehydrate() { @Override public ListenableFuture<Executor> rehydrate() {
Queue.Item item = Queue.getInstance().schedule2(task, 0).getItem(); return new TryRepeatedly<Executor>(1, 0) {
if (item == null) { Future<Queue.Executable> future;
// TODO should also report when !ScheduleResult.created, since that is arguably an error
return Futures.immediateFailedFuture(new IllegalStateException("queue refused " + task));
}

final Future<Queue.Executable> future = item.getFuture().getStartCondition();

return new TryRepeatedly<Executor>(1) {
@Override @Override
protected Executor tryResolve() throws Exception { protected Executor tryResolve() throws Exception {
if (future == null) {
Queue.Item item = Queue.getInstance().schedule2(task, 0).getItem();
if (item == null) {
// TODO should also report when !ScheduleResult.created, since that is arguably an error
throw new IllegalStateException("queue refused " + task);
}
future = item.getFuture().getStartCondition();
}

if (!future.isDone()) { if (!future.isDone()) {
return null; return null;
} }
Expand Down
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -38,15 +38,19 @@
* @author Kohsuke Kawaguchi * @author Kohsuke Kawaguchi
*/ */
public abstract class TryRepeatedly<V> extends AbstractFuture<V> { public abstract class TryRepeatedly<V> extends AbstractFuture<V> {
private final int seconds; private final int delay;
private ScheduledFuture<?> next; private ScheduledFuture<?> next;


protected TryRepeatedly(int seconds) { protected TryRepeatedly(int delay) {
this.seconds = seconds; this(delay, delay);
tryLater();
} }


private void tryLater() { protected TryRepeatedly(int delay, int initialDelay) {
this.delay = delay;
tryLater(initialDelay);
}

private void tryLater(int currentDelay) {
// TODO log a warning if trying for too long; probably Pickle.rehydrate should be given a TaskListener to note progress // TODO log a warning if trying for too long; probably Pickle.rehydrate should be given a TaskListener to note progress


if (isCancelled()) return; if (isCancelled()) return;
Expand All @@ -57,14 +61,14 @@ public void run() {
try { try {
V v = tryResolve(); V v = tryResolve();
if (v == null) if (v == null)
tryLater(); tryLater(delay);
else else
set(v); set(v);
} catch (Throwable t) { } catch (Throwable t) {
setException(t); setException(t);
} }
} }
}, seconds, TimeUnit.SECONDS); }, currentDelay, TimeUnit.SECONDS);
} }


@Override @Override
Expand Down
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -348,8 +348,13 @@ private static void finish(@CheckForNull String cookie) {
LOGGER.log(FINE, "no running task corresponds to {0}", cookie); LOGGER.log(FINE, "no running task corresponds to {0}", cookie);
return; return;
} }
assert runningTask.execution != null && runningTask.launcher != null; final AsynchronousExecution execution = runningTask.execution;
runningTask.execution.completed(null); assert execution != null && runningTask.launcher != null;
Timer.get().submit(new Runnable() { // JENKINS-31614
@Override public void run() {
execution.completed(null);
}
});
try { try {
runningTask.launcher.kill(Collections.singletonMap(COOKIE_VAR, cookie)); runningTask.launcher.kill(Collections.singletonMap(COOKIE_VAR, cookie));
} catch (ChannelClosedException x) { } catch (ChannelClosedException x) {
Expand Down

0 comments on commit cb65b31

Please sign in to comment.