144 lines
4.9 KiB
Java
144 lines
4.9 KiB
Java
/*
|
|
*
|
|
* Copyright 2013 OpenStack Foundation
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*
|
|
*/
|
|
package hudson.plugins.gearman;
|
|
|
|
import jenkins.model.Jenkins;
|
|
import hudson.model.Queue;
|
|
import hudson.model.Computer;
|
|
|
|
import org.slf4j.Logger;
|
|
import org.slf4j.LoggerFactory;
|
|
|
|
public class NodeAvailabilityMonitor implements AvailabilityMonitor {
|
|
private final Queue queue;
|
|
private final Jenkins jenkins;
|
|
private final Computer computer;
|
|
private MyGearmanWorkerImpl workerHoldingLock = null;
|
|
private String expectedUUID = null;
|
|
|
|
private static final Logger logger = LoggerFactory
|
|
.getLogger(Constants.PLUGIN_LOGGER_NAME);
|
|
|
|
NodeAvailabilityMonitor(Computer computer)
|
|
{
|
|
this.computer = computer;
|
|
queue = Queue.getInstance();
|
|
jenkins = Jenkins.getInstance();
|
|
}
|
|
|
|
public Computer getComputer() {
|
|
return computer;
|
|
}
|
|
|
|
public void lock(MyGearmanWorkerImpl worker)
|
|
throws InterruptedException
|
|
{
|
|
logger.debug("AvailabilityMonitor lock request: " + worker);
|
|
while (true) {
|
|
boolean busy = false;
|
|
|
|
// Synchronize on the Jenkins queue so that Jenkins is
|
|
// unable to schedule builds while we try to acquire the
|
|
// lock.
|
|
synchronized(queue) {
|
|
if (workerHoldingLock == null) {
|
|
if (computer.countIdle() == 0) {
|
|
// If there are no idle executors, we can not
|
|
// schedule a build.
|
|
busy = true;
|
|
} else if (jenkins.isQuietingDown()) {
|
|
busy = true;
|
|
} else {
|
|
logger.debug("AvailabilityMonitor got lock: " + worker);
|
|
workerHoldingLock = worker;
|
|
return;
|
|
}
|
|
} else {
|
|
busy = true;
|
|
}
|
|
}
|
|
if (busy) {
|
|
synchronized(this) {
|
|
// We get synchronous notification when a
|
|
// build finishes, but there are lots of other
|
|
// reasons circumstances could change (adding
|
|
// an executor, canceling shutdown, etc), so
|
|
// we slowly busy wait to cover all those
|
|
// reasons.
|
|
this.wait(5000);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public void unlock(MyGearmanWorkerImpl worker) {
|
|
logger.debug("AvailabilityMonitor unlock request: " + worker);
|
|
synchronized(queue) {
|
|
if (workerHoldingLock == worker) {
|
|
workerHoldingLock = null;
|
|
expectedUUID = null;
|
|
logger.debug("AvailabilityMonitor unlocked: " + worker);
|
|
} else {
|
|
logger.debug("Worker does not own AvailabilityMonitor lock: " +
|
|
worker);
|
|
}
|
|
}
|
|
wake();
|
|
}
|
|
|
|
public void wake() {
|
|
// Called when we know circumstances may have changed in a way
|
|
// that may allow someone to get the lock.
|
|
logger.debug("AvailabilityMonitor wake request");
|
|
synchronized(this) {
|
|
logger.debug("AvailabilityMonitor woken");
|
|
notifyAll();
|
|
}
|
|
}
|
|
|
|
public void expectUUID(String UUID) {
|
|
// The Gearman worker which holds the lock is about to
|
|
// schedule this build, so when Jenkins asks to run it, say
|
|
// "yes".
|
|
if (expectedUUID != null) {
|
|
logger.error("AvailabilityMonitor told to expect UUID " +
|
|
UUID + "while already expecting " + expectedUUID);
|
|
}
|
|
expectedUUID = UUID;
|
|
}
|
|
|
|
public boolean canTake(Queue.BuildableItem item)
|
|
{
|
|
// Jenkins calls this from within the scheduler maintenance
|
|
// function (while owning the queue monitor). If we are
|
|
// locked, only allow the build we are expecting to run.
|
|
logger.debug("AvailabilityMonitor canTake request for " +
|
|
workerHoldingLock);
|
|
|
|
NodeParametersAction param = item.getAction(NodeParametersAction.class);
|
|
if (param != null) {
|
|
logger.debug("AvailabilityMonitor canTake request for UUID " +
|
|
param.getUuid() + " expecting " + expectedUUID);
|
|
|
|
if (expectedUUID == param.getUuid()) {
|
|
return true;
|
|
}
|
|
}
|
|
return (workerHoldingLock == null);
|
|
}
|
|
} |