/** Shutdown the scheduler. All subsequent execution request will be rejected. */ public void shutdown() throws InterruptedException { checkState(!_isShutdown); _isShutdown = true; /* Drain jobs from the queue so they will never be started. Has to be done * before killing jobs as otherwise the queued jobs will immediatley fill * the freed job slot. */ Collection<PrioritizedRequest> toBeCancelled = new ArrayList<>(); _queue.drainTo(toBeCancelled); /* Kill both the jobs that were queued and which are running. */ _jobs.values().forEach(j -> j.kill("shutdown")); /* Jobs that were queued were never submitted for execution and thus we * manually trigger postprocessing. */ toBeCancelled.forEach(this::postprocessWithoutJobSlot); LOGGER.info("Waiting for movers on queue '{}' to finish", _name); if (!_semaphore.tryAcquire(_semaphore.getMaxPermits(), 2, TimeUnit.SECONDS)) { // This is often due to a mover not reacting to interrupt or the transfer // doing a lengthy checksum calculation during post processing. String versions = _jobs .values() .stream() .map(PrioritizedRequest::getMover) .map(Mover::getProtocolInfo) .map(ProtocolInfo::getVersionString) .collect(joining(",")); LOGGER.warn("Failed to terminate some movers prior to shutdown: {}", versions); } }
/** * Set maximal number of concurrently running jobs by this scheduler. All pending jobs will be * executed. * * @param maxJobs */ public void setMaxActiveJobs(int maxJobs) { _semaphore.setMaxPermits(maxJobs); PrioritizedRequest request; while (_semaphore.tryAcquire() && (request = nextOrRelease()) != null) { sendToExecution(request); } }
public MoverRequestScheduler(String name, int queueId, Order order) { _name = name; _queueId = queueId; _order = order; _queue = createQueue(order); _semaphore.setMaxPermits(2); }
/** * Returns the next job or releases a job slot. If a non-null value is returned, the caller must * submit the job to execution. Should only be caller by a caller than currently holds a job slot. * * @return */ private synchronized PrioritizedRequest nextOrRelease() { PrioritizedRequest request = _queue.poll(); if (request == null) { _semaphore.release(); } return request; }
/** * Add a request to the scheduler. * * <p>Returns true if the caller acquired a job slot and must send the job to execution. * * @param request * @return */ private synchronized boolean submit(PrioritizedRequest request) { if (_jobs.put(request.getId(), request) != null) { throw new RuntimeException( "Duplicate mover id detected. Please report to [email protected]."); } if (_semaphore.tryAcquire()) { return true; } else { _queue.add(request); return false; } }
/** * Get mover id for given door request. If there is no mover associated with {@code * doorUniqueueRequest} a new mover will be created by using provided {@code moverSupplier}. * * <p>The returned mover id generated with following encoding: | 31- queue id -24|23- job id -0| * * @param moverSupplier {@link MoverSupplier} which can create a mover for given requests. * @param doorUniqueId unique request identifier generated by the door. * @param priority * @return mover id */ public int getOrCreateMover(MoverSupplier moverSupplier, String doorUniqueId, IoPriority priority) throws CacheException { checkState(!_isShutdown); try { /* Create the request if it doesn't already exists. */ PrioritizedRequest request = _moverByRequests.computeIfAbsent( doorUniqueId, key -> { try { return createRequest(moverSupplier, key, priority); } catch (CacheException e) { throw new RuntimeException(e); } }); /* If not already queued, submit it. */ if (request.queue()) { if (submit(request)) { /* There was a free slot in the queue so we submit directly to execution. */ sendToExecution(request); } else if (_semaphore.getMaxPermits() <= 0) { LOGGER.warn( "A task was added to queue '{}', however the queue is not " + "configured to execute any tasks.", _name); } } return request.getId(); } catch (RuntimeException e) { Throwables.propagateIfInstanceOf(e.getCause(), CacheException.class); throw e; } }
/** * Get the maximal number allowed of concurrently running jobs by this scheduler. * * @return maximal number of jobs. */ public int getMaxActiveJobs() { return _semaphore.getMaxPermits(); }