/*
* Copyright (c) NASK, NCSC
*
* This file is part of HoneySpider Network 2.1.
*
* This is a free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package pl.nask.hsn2.suppressor;
import java.util.Properties;
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.Semaphore;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import pl.nask.hsn2.bus.connector.process.ProcessConnectorException;
import pl.nask.hsn2.framework.suppressor.JobSuppressorHelper;
import pl.nask.hsn2.framework.suppressor.SingleThreadTasksSuppressor;
import pl.nask.hsn2.framework.workflow.job.TasksStatistics;
public final class JobSuppressorHelperImpl implements JobSuppressorHelper {
private static final Logger LOGGER = LoggerFactory.getLogger(JobSuppressorHelperImpl.class);
private BlockingDeque<TaskRequestDataContainer> waitingRequests = new LinkedBlockingDeque<>();
private final Semaphore semaphore;
private final long jobId;
private final SingleThreadTasksSuppressor mainSuppressor;
public JobSuppressorHelperImpl(long jobId, int tasksThresholdNumber, SingleThreadTasksSuppressor mainSuppressor) {
this.jobId = jobId;
this.mainSuppressor = mainSuppressor;
waitingRequests = new LinkedBlockingDeque<>();
semaphore = new Semaphore(tasksThresholdNumber);
}
@Override
public void tryToSendRequest() {
if (semaphore.tryAcquire()) {
// At this point semaphore is acquired.
if (waitingRequests.isEmpty()) {
// Nothing to do - release semaphore.
semaphore.release();
LOGGER.debug("Nothing to do this time...");
} else {
sendRequest();
}
}
}
@Override
public void addTaskRequest(String serviceName, String serviceLabel, int taskId, long objectDataId, Properties serviceParameters,
TasksStatistics stats) {
LOGGER.debug("Adding new task to waiting list.", serviceLabel);
// Add to waiting requests.
TaskRequestDataContainer trd = new TaskRequestDataContainer(serviceName, serviceLabel, taskId, objectDataId, serviceParameters,
stats);
waitingRequests.push(trd);
stats.updateSuppressorStats(getFreeBuforSpacesCount(), getWaitingTasksRequestsCount());
// Inform main suppressor there is an action to do.
mainSuppressor.notifyAboutJobStateChange(this);
LOGGER.debug("Task added to waiting list. (job={}, id={}, service={})", new Object[] { jobId, taskId, serviceLabel });
}
@Override
public void signalTaskCompletion(Long jobId, Integer taskId, TasksStatistics stats) {
// Release semaphore.
semaphore.release();
stats.updateSuppressorStats(getFreeBuforSpacesCount(), getWaitingTasksRequestsCount());
// Inform main suppressor job status has changed.
mainSuppressor.notifyAboutJobStateChange(this);
LOGGER.debug("Task completion signal received. Buffer's space released. (job={}, task={}, freeSpace={}, waitingList={})",
new Object[] { jobId, taskId, getFreeBuforSpacesCount(), getWaitingTasksRequestsCount() });
}
@Override
public int getWaitingTasksRequestsCount() {
return waitingRequests.size();
}
@Override
public int getFreeBuforSpacesCount() {
return semaphore.availablePermits();
}
private void sendRequest() {
TaskRequestDataContainer taskRequestData = waitingRequests.pop();
taskRequestData.getStats().updateSuppressorStats(getFreeBuforSpacesCount(), getWaitingTasksRequestsCount());
LOGGER.debug("Action will be taken. (job={}, task={}, freeSpace={}, waitingList={})",
new Object[] { jobId, taskRequestData.getTaskId(), getFreeBuforSpacesCount(), getWaitingTasksRequestsCount() });
try {
JobSuppressorUtils.sendTaskRequest(jobId, getFreeBuforSpacesCount(), getWaitingTasksRequestsCount(),
taskRequestData.getStats(), taskRequestData.getServiceName(), taskRequestData.getServiceId(),
taskRequestData.getTaskId(), taskRequestData.getObjectDataId(), taskRequestData.getParams());
} catch (ProcessConnectorException e) {
LOGGER.error(e.getMessage(), e);
System.exit(1); // TODO: doggy! fix it ASAP! Maybe internal TaskError operation?
}
LOGGER.debug("Task request sent for service.(job={}, task={}, service={})", new Object[] { jobId, taskRequestData.getTaskId(),
taskRequestData.getServiceId() });
}
}