package com.griddynamics.jagger.engine.e1.process;
import com.griddynamics.jagger.coordinator.NodeContext;
import com.griddynamics.jagger.engine.e1.scenario.WorkloadConfiguration;
import com.griddynamics.jagger.exception.TechnicalException;
import com.griddynamics.jagger.util.Futures;
import com.griddynamics.jagger.util.TimeoutsConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.google.common.util.concurrent.Service;
import java.util.Collection;
import java.util.Iterator;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.atomic.AtomicInteger;
public class PerThreadWorkloadProcess extends AbstractWorkloadProcess {
private static final Logger log = LoggerFactory.getLogger(PerThreadWorkloadProcess.class);
private int totalSamplesCountRequested;
private final AtomicInteger leftSamplesCount = new AtomicInteger(-1);
public PerThreadWorkloadProcess(String sessionId, StartWorkloadProcess command, NodeContext context, ThreadPoolExecutor executor, TimeoutsConfiguration timeoutsConfiguration) {
super(executor, sessionId, command, context, timeoutsConfiguration);
}
@Override
protected Collection<WorkloadService> getRunningWorkloadServiceCollection() {
return Lists.newLinkedList();
}
@Override
public void start() throws TechnicalException {
log.debug("Going to execute command {}.", command);
super.start();
}
@Override
protected void doStart() {
int delay = command.getScenarioContext().getWorkloadConfiguration().getDelay();
totalSamplesCountRequested = command.getScenarioContext().getWorkloadConfiguration().getSamples();
leftSamplesCount.set(totalSamplesCountRequested);
for (int i = 0; i < command.getThreads(); i++) {
startNewThread(delay);
}
log.debug("Threads are scheduled");
}
@Override
protected WorkloadService getService(AbstractWorkloadService.WorkloadServiceBuilder builder) {
return ( predefinedSamplesCount()) ? builder.buildServiceWithSharedSamplesCount(leftSamplesCount) : builder.buildInfiniteService();
}
private boolean predefinedSamplesCount() {
return totalSamplesCountRequested != -1;
}
@Override
public void changeConfiguration(WorkloadConfiguration configuration) {
log.debug("Configuration change request received");
for (Iterator<WorkloadService> it = threads.iterator(); it.hasNext(); ){
WorkloadService workloadService = it.next();
if (workloadService.state().equals(Service.State.TERMINATED)) {
it.remove();
samplesCountStartedFromTerminatedThreads += workloadService.getStartedSamples();
samplesCountFinishedFromTerminatedThreads += workloadService.getFinishedSamples();
emptyTransactionsFromTerminatedThreads += workloadService.getEmptyTransactions();
}
}
final int threadDiff = configuration.getThreads() - threads.size();
if (threadDiff < 0) {
log.debug("Going to decrease thread count by {}", threadDiff);
removeThreads(Math.abs(threadDiff));
}
if (totalSamplesCountRequested != configuration.getSamples()) {
leftSamplesCount.addAndGet(configuration.getSamples() - totalSamplesCountRequested);
totalSamplesCountRequested = configuration.getSamples();
}
int delay = configuration.getDelay();
if (threadDiff > 0 && (!predefinedSamplesCount() || leftSamplesCount.get() > 0)) {
log.debug("Going to increase thread count by {}", threadDiff);
for (int i = threadDiff; i > 0; i--) {
startNewThread(delay);
}
}
log.debug("Delay should be changed to {}", delay);
for (WorkloadService thread : threads) {
thread.changeDelay(delay);
}
}
private void removeThreads(int count) {
Preconditions.checkState(!threads.isEmpty());
Preconditions.checkState(threads.size() >= count);
Collection<Future<Service.State>> futures = Lists.newLinkedList();
Iterator<WorkloadService> iterator = threads.iterator();
for (int i=0; i<count; i++){
WorkloadService service = iterator.next();
futures.add(service.stop());
}
for (Future<Service.State> future : futures){
Futures.get(future, timeoutsConfiguration.getWorkloadStopTimeout());
}
}
}