/*******************************************************************************
* Copyright (c) 2014 Imperial College London
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Raul Castro Fernandez - initial API and implementation
******************************************************************************/
package uk.ac.imperial.lsds.seep.infrastructure.monitor;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import uk.ac.imperial.lsds.seep.infrastructure.master.Infrastructure;
import uk.ac.imperial.lsds.seep.infrastructure.monitor.policy.util.InfrastructureAdaptor;
import uk.ac.imperial.lsds.seep.operator.Operator;
/**
* Adaptor class to allow the monitoring framework to interact with SEEP, maintaining
* a relatively loose coupling between the two. The monitoring layer will always
* call SEEP by means of this adaptor and never directly. There is a single point
* of integration for the interface framework -> SEEP.
*
* @author mrouaux
*/
public class SeepInfrastructureAdaptor implements InfrastructureAdaptor {
final private Logger logger = LoggerFactory.getLogger(SeepInfrastructureAdaptor.class);
private Infrastructure infrastructure;
private Map<Integer, Integer> originalSizes;
/**
* Convenience constructor.
* @param infrastructure
*/
public SeepInfrastructureAdaptor(Infrastructure infrastructure) {
this.infrastructure = infrastructure;
}
/**
* Returns list of logical operator identifiers in the current query.
* @return
*/
@Override
public List<Integer> getOperatorIds() {
List<Integer> operatorIds = new ArrayList<Integer>();
for(Operator op : infrastructure.getOps()) {
operatorIds.add(op.getOperatorId());
}
return operatorIds;
}
/**
* Returns current size for a given logical operator identifier in the current
* query (counts physical instances of logical operator).
* @param operatorId Operator identifier from the logical query.
* @return Number of physical instances executing the operator.
*/
@Override
public int getOperatorCurrentSize(int operatorId) {
List<Integer> nodeIds = infrastructure.getEiu().getNodeIdsForOperatorId(operatorId);
int currSize = 0;
if (nodeIds != null) {
for(Integer nodeId : nodeIds) {
// logger.debug("operatorId=" + operatorId + " running at node nodeId=" + nodeId);
}
currSize = nodeIds.size();
}
return currSize;
}
/**
* Sets the new size for a given logical operator identifier.
* @param operatorId Operator identifier in the logical query.
* @param size Size to achieve for the operator (as number of physical
* instances of the logical operator).
*/
@Override
public void setOperatorScaledSize(int operatorId, int size) {
// Get the current size for the operator
int currSize = getOperatorCurrentSize(operatorId);
logger.info("operatorId=" + operatorId + " currSize=" + currSize);
logger.info("operatorId=" + operatorId + " newSize=" + size);
// If the desired size is greater than the current operator size, there
// are fewer nodes that necessary and we need to scale out. The elastic
// tools only provide a method to scale operators by one, we might need
// to scale a few times to achieve the desired size.
if (size > currSize) {
logger.info("Scaling out operatorId=" + operatorId + " from currentSize="
+ currSize + " to newSize=" + size);
for(int i = 0; i < size - currSize; i++) {
infrastructure.getEiu().alert(operatorId);
}
} else if (size < currSize) {
logger.info("Scaling in operatorId=" + operatorId + " from currentSize="
+ currSize + " to newSize=" + size);
for(int i = 0; i < currSize - size; i++) {
infrastructure.getEiu().unalertCPU(operatorId);
}
}
}
/**
* Original size of a given operator identifier in the logical query. In most
* cases this is just going to be 1.
* @param operatorId Operator identifier in the logical query.
* @return Typically, the value 1.
*/
@Override
public int getOperatorOriginalSize(int operatorId) {
if(!originalSizes.containsKey(operatorId)) {
// Use the current size as the original size if we haven't recorded this yet
originalSizes.put(operatorId, getOperatorCurrentSize(operatorId));
}
return originalSizes.get(operatorId);
}
}