package org.apache.hadoop.corona;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.conf.Configured;
import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.map.ObjectMapper;
public class CoronaConf extends Configuration {
public static final Log LOG = LogFactory.getLog(CoronaConf.class);
public static final String CM_ADDRESS = "cm.server.address";
public static final String CM_HTTP_ADDRESS = "cm.server.http.address";
public static final String NODE_EXPIRY_INTERVAL = "cm.node.expiryinterval";
public static final String SESSION_EXPIRY_INTERVAL = "cm.session.expiryinterval";
public static final String NOTIFIER_POLL_INTERVAL = "cm.notifier.pollinterval";
public static final String NOTIFIER_RETRY_INTERVAL_FACTOR = "cm.notifier.retry.interval.factor";
public static final String NOTIFIER_RETRY_INTERVAL_START = "cm.notifier.retry.interval.start";
public static final String NOTIFIER_RETRY_MAX = "cm.notifier.retry.max";
public static final String CPU_TO_RESOURCE_PARTITIONING = "cm.cpu.to.resource.partitioning";
public static final String CM_SOTIMEOUT = "cm.server.sotimeout";
public static final String NODE_RESERVED_MEMORY_MB = "cm.node.reserved.memory.mb";
public static final String NODE_RESERVED_DISK_GB = "cm.node.reserved.disk.gb";
// these are left in the mapred.fairscheduler namespace to make sure they are
// compatible with the current fairscheduler. client can be expected to send jobs
// to corona and/or classic hadoop with same configuration
public static final String IMPLICIT_POOL_PROPERTY = "mapred.fairscheduler.poolnameproperty";
public static final String EXPLICIT_POOL_PROPERTY = "mapred.fairscheduler.pool";
public static final String POOL_CONFIG_FILE = "corona.xml";
private Map<Integer, Map<String, Integer>> cachedCpuToResourcePartitioning = null;
public CoronaConf(Configuration conf) {
super(conf);
}
public int getCMSoTimeout() {
return getInt(CM_SOTIMEOUT, 30*1000);
}
public String getClusterManagerAddress() {
return get(CM_ADDRESS, "localhost:8888");
}
public String getClusterManagerHttpAddress() {
return get(CM_HTTP_ADDRESS, "localhost:0");
}
public static String getClusterManagerAddress(Configuration conf) {
return conf.get(CM_ADDRESS, "localhost:8888");
}
public int getNodeExpiryInterval() {
return getInt(NODE_EXPIRY_INTERVAL, 10 * 60 * 1000);
}
public int getSessionExpiryInterval() {
int val = getInt(SESSION_EXPIRY_INTERVAL, 0);
if (val != 0)
return val;
// if the session expiry interval is not specified then we compute
// one based on the exponential backoff intervals of the session
// notification retries
val = getNotifierRetryIntervalStart();
int factor = getNotifierRetryIntervalFactor();
for(int i=1; i<getNotifierRetryMax(); i++) {
val += val*factor;
}
return val;
}
public int getNotifierPollInterval() {
return getInt(NOTIFIER_POLL_INTERVAL, 1000);
}
public int getNotifierRetryIntervalFactor() {
return getInt(NOTIFIER_RETRY_INTERVAL_FACTOR, 4);
}
public int getNotifierRetryIntervalStart() {
return getInt(NOTIFIER_RETRY_INTERVAL_START, 5000);
}
public int getNotifierRetryMax() {
return getInt(NOTIFIER_RETRY_MAX, 5);
}
public Map<Integer, Map<String, Integer>> getCpuToResourcePartitioning() {
if (cachedCpuToResourcePartitioning != null)
return cachedCpuToResourcePartitioning;
String jsonStr = get(CPU_TO_RESOURCE_PARTITIONING, "");
Map<Integer, Map<String, Integer>> ret = new HashMap<Integer, Map<String, Integer>> ();
try {
ObjectMapper mapper = new ObjectMapper();
JsonNode rootNode = mapper.readValue(jsonStr, JsonNode.class);
Iterator<String> iter = rootNode.getFieldNames();
while (iter.hasNext()) {
String field = iter.next();
Integer numCpu = Integer.parseInt(field);
if ((numCpu < 0) || (numCpu > 64)) {
throw new RuntimeException("Number of CPUs: " + numCpu + " is not in range 0-64");
}
JsonNode val = rootNode.get(field);
if (!val.isObject()) {
throw new RuntimeException("Resource Partitioning: " + val.toString() + " is not a object");
}
HashMap<String, Integer> resourcePartition = null;
Iterator<String> valIter = val.getFieldNames();
while (valIter.hasNext()) {
String resourceType = valIter.next();
JsonNode resourceVal = val.get(resourceType);
int resourceSlots = 0;
if (!resourceVal.isInt() || ((resourceSlots = resourceVal.getIntValue()) < 0) ||
resourceSlots > 64) {
throw new RuntimeException("Resource Partition value: " + resourceVal.toString() +
" is not a valid number");
}
if (resourcePartition == null) {
resourcePartition = new HashMap<String, Integer> ();
}
resourcePartition.put(resourceType, new Integer(resourceSlots));
}
if (resourcePartition != null) {
ret.put(numCpu, resourcePartition);
}
}
return ret;
} catch (Exception e) {
LOG.error(jsonStr + " is not a valid value for option: " + CPU_TO_RESOURCE_PARTITIONING);
throw new RuntimeException (e);
}
}
public String getPoolName() {
String poolNameProperty = get(IMPLICIT_POOL_PROPERTY, "user.name");
return get(EXPLICIT_POOL_PROPERTY, get(poolNameProperty, "")).trim();
}
public int getNodeReservedMemoryMB() {
return getInt(NODE_RESERVED_MEMORY_MB, 0);
}
public int getNodeReservedDiskGB() {
return getInt(NODE_RESERVED_DISK_GB, 0);
}
}