/*
* Copyright (c) 2010-2012 Grid Dynamics Consulting Services, Inc, All Rights Reserved
* http://www.griddynamics.com
*
* This library is free software; you can redistribute it and/or modify it under the terms of
* the Apache License; either
* version 2.0 of the License, or any later version.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.griddynamics.jagger.engine.e1.scenario;
import com.google.common.collect.Maps;
import com.griddynamics.jagger.coordinator.NodeId;
import com.griddynamics.jagger.util.SystemClock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.math.BigDecimal;
import java.util.Map;
import java.util.Set;
/**
* @author Nikolay Musienko
* Date: 28.06.13
*/
abstract class AbstractRateClock implements WorkloadClock {
private static final Logger log = LoggerFactory.getLogger(AbstractRateClock.class);
private final int tickInterval;
private final TpsRouter tpsRouter;
private final WorkloadSuggestionMaker workloadSuggestionMaker;
private final SystemClock systemClock;
private final Map<NodeId, NodeTpsRecorder> tpsStat;
private final int maxThreads;
public AbstractRateClock(int tickInterval, TpsRouter tpsRouter, WorkloadSuggestionMaker workloadSuggestionMaker, SystemClock systemClock, int maxThreads) {
this.tickInterval = tickInterval;
this.tpsRouter = tpsRouter;
this.workloadSuggestionMaker = workloadSuggestionMaker;
this.systemClock = systemClock;
this.maxThreads = maxThreads;
tpsStat = Maps.newHashMap();
}
@Override
public Map<NodeId, Integer> getPoolSizes(Set<NodeId> nodes) {
Map<NodeId, Integer> result = Maps.newHashMap();
for (NodeId node : nodes) {
result.put(node, maxThreads);
}
return result;
}
@Override
public void tick(WorkloadExecutionStatus status, WorkloadAdjuster adjuster) {
log.debug("Going to perform tick with status {}", status);
Map<NodeId, WorkloadConfiguration> configUpdate = suggestConfigurationUpdate(status);
for (Map.Entry<NodeId, WorkloadConfiguration> entry : configUpdate.entrySet()) {
NodeId node = entry.getKey();
WorkloadConfiguration configuration = entry.getValue();
log.debug("Going to change configuration on node {} to {}", node, configuration);
adjuster.adjustConfiguration(node, configuration);
}
}
private Map<NodeId, WorkloadConfiguration> suggestConfigurationUpdate(WorkloadExecutionStatus status) {
log.debug("Recording current status");
recordStatus(status);
log.debug("Current status recorded");
log.debug("Going to recalculate desired tps per node");
Map<NodeId, BigDecimal> desiredTpsPerNode = tpsRouter.getDesiredTpsPerNode(tpsStat);
log.debug("Desired tps per node recalculated");
log.debug("Desired tps per node is {}", desiredTpsPerNode);
log.debug("Going to suggest new workload configurations for kernels");
Map<NodeId, WorkloadConfiguration> result = Maps.newHashMap();
for (NodeId node : status.getNodes()) {
WorkloadConfiguration suggestion = workloadSuggestionMaker.suggest(desiredTpsPerNode.get(node), tpsStat.get(node), maxThreads);
log.debug("Suggested {} for node {}", suggestion, node);
result.put(node, suggestion);
}
return result;
}
private void recordStatus(WorkloadExecutionStatus status) {
if (tpsStat.isEmpty()) {
for (NodeId node : status.getNodes()) {
NodeTpsRecorder recorder = new NodeTpsRecorder(20);
recorder.recordStatus(0, 0, 0, systemClock.currentTimeMillis());
tpsStat.put(node, recorder);
}
return;
}
for (NodeId node : status.getNodes()) {
NodeTpsRecorder nodeTpsRecorder = tpsStat.get(node);
Integer delay = status.getDelay(node);
Integer threads = status.getThreads(node);
Integer samples = getSamples(status, node);
Long pollTime = status.getPollTime(node);
nodeTpsRecorder.recordStatus(threads, delay, samples, pollTime);
}
}
protected abstract Integer getSamples(WorkloadExecutionStatus status, NodeId node);
//Need to have 2 implements (Rps and Tps)
@Override
public int getTickInterval() {
return tickInterval;
}
@Override
public int getValue() {
return tpsRouter.getDesiredTps().intValue();
}
}