package com.hubspot.singularity.data;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.utils.ZKPaths;
import com.codahale.metrics.MetricRegistry;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import com.hubspot.singularity.SingularityCreateResult;
import com.hubspot.singularity.SingularityDeleteResult;
import com.hubspot.singularity.SingularitySlaveUsage;
import com.hubspot.singularity.SingularitySlaveUsageWithId;
import com.hubspot.singularity.SingularityTaskCurrentUsage;
import com.hubspot.singularity.SingularityTaskCurrentUsageWithId;
import com.hubspot.singularity.SingularityTaskId;
import com.hubspot.singularity.SingularityTaskUsage;
import com.hubspot.singularity.config.SingularityConfiguration;
import com.hubspot.singularity.data.transcoders.Transcoder;
@Singleton
public class UsageManager extends CuratorAsyncManager {
private static final String ROOT_PATH = "/usage";
private static final String SLAVE_PATH = ROOT_PATH + "/slaves";
private static final String TASK_PATH = ROOT_PATH + "/tasks";
private static final String USAGE_HISTORY_PATH_KEY = "history";
private static final String CURRENT_USAGE_NODE_KEY = "CURRENT";
private final Transcoder<SingularitySlaveUsage> slaveUsageTranscoder;
private final Transcoder<SingularityTaskUsage> taskUsageTranscoder;
private final Transcoder<SingularityTaskCurrentUsage> taskCurrentUsageTranscoder;
@Inject
public UsageManager(CuratorFramework curator, SingularityConfiguration configuration, MetricRegistry metricRegistry, Transcoder<SingularitySlaveUsage> slaveUsageTranscoder,
Transcoder<SingularityTaskUsage> taskUsageTranscoder, Transcoder<SingularityTaskCurrentUsage> taskCurrentUsageTranscoder) {
super(curator, configuration, metricRegistry);
this.slaveUsageTranscoder = slaveUsageTranscoder;
this.taskUsageTranscoder = taskUsageTranscoder;
this.taskCurrentUsageTranscoder = taskCurrentUsageTranscoder;
}
public List<String> getSlavesWithUsage() {
return getChildren(SLAVE_PATH);
}
public List<String> getTasksWithUsage() {
return getChildren(TASK_PATH);
}
// /slaves/<slaveid>/CURRENT
private String getSlaveIdFromCurrentUsagePath(String path) {
return path.substring(path.indexOf(SLAVE_PATH) + SLAVE_PATH.length() + 1, path.lastIndexOf("/"));
}
// /tasks/<taskid>/CURRENT
private String getTaskIdFromCurrentUsagePath(String path) {
return path.substring(path.indexOf(TASK_PATH) + TASK_PATH.length() + 1, path.lastIndexOf("/"));
}
private String getSlaveUsagePath(String slaveId) {
return ZKPaths.makePath(SLAVE_PATH, slaveId);
}
private String getTaskUsagePath(String taskId) {
return ZKPaths.makePath(TASK_PATH, taskId);
}
private String getSlaveUsageHistoryPath(String slaveId) {
return ZKPaths.makePath(getSlaveUsagePath(slaveId), USAGE_HISTORY_PATH_KEY);
}
private String getTaskUsageHistoryPath(String taskId) {
return ZKPaths.makePath(getTaskUsagePath(taskId), USAGE_HISTORY_PATH_KEY);
}
private String getSpecificSlaveUsagePath(String slaveId, long timestamp) {
return ZKPaths.makePath(getSlaveUsageHistoryPath(slaveId), Long.toString(timestamp));
}
private String getSpecificTaskUsagePath(String taskId, double timestamp) {
return ZKPaths.makePath(getTaskUsageHistoryPath(taskId), Double.toString(timestamp));
}
private String getCurrentSlaveUsagePath(String slaveId) {
return ZKPaths.makePath(getSlaveUsagePath(slaveId), CURRENT_USAGE_NODE_KEY);
}
private String getCurrentTaskUsagePath(String taskId) {
return ZKPaths.makePath(getTaskUsagePath(taskId), CURRENT_USAGE_NODE_KEY);
}
public SingularityDeleteResult deleteSlaveUsage(String slaveId) {
return delete(getSlaveUsagePath(slaveId));
}
public SingularityDeleteResult deleteTaskUsage(String taskId) {
return delete(getTaskUsagePath(taskId));
}
public SingularityDeleteResult deleteSpecificSlaveUsage(String slaveId, long timestamp) {
return delete(getSpecificSlaveUsagePath(slaveId, timestamp));
}
public SingularityDeleteResult deleteSpecificTaskUsage(String taskId, double timestamp) {
return delete(getSpecificTaskUsagePath(taskId, timestamp));
}
public SingularityCreateResult saveCurrentTaskUsage(String taskId, SingularityTaskCurrentUsage usage) {
return set(getCurrentTaskUsagePath(taskId), usage, taskCurrentUsageTranscoder);
}
public SingularityCreateResult saveSpecificTaskUsage(String taskId, SingularityTaskUsage usage) {
return save(getSpecificTaskUsagePath(taskId, usage.getTimestamp()), usage, taskUsageTranscoder);
}
public SingularityCreateResult saveSpecificSlaveUsageAndSetCurrent(String slaveId, SingularitySlaveUsage usage) {
set(getCurrentSlaveUsagePath(slaveId), usage, slaveUsageTranscoder);
return save(getSpecificSlaveUsagePath(slaveId, usage.getTimestamp()), usage, slaveUsageTranscoder);
}
private static final Comparator<SingularitySlaveUsage> SLAVE_USAGE_COMPARATOR_TIMESTAMP_ASC = new Comparator<SingularitySlaveUsage>() {
@Override
public int compare(SingularitySlaveUsage o1, SingularitySlaveUsage o2) {
return Long.compare(o1.getTimestamp(), o2.getTimestamp());
}
};
public List<SingularitySlaveUsage> getSlaveUsage(String slaveId) {
List<SingularitySlaveUsage> children = getAsyncChildren(getSlaveUsageHistoryPath(slaveId), slaveUsageTranscoder);
Collections.sort(children, SLAVE_USAGE_COMPARATOR_TIMESTAMP_ASC);
return children;
}
private static final Comparator<SingularityTaskUsage> TASK_USAGE_COMPARATOR_TIMESTAMP_ASC = new Comparator<SingularityTaskUsage>() {
@Override
public int compare(SingularityTaskUsage o1, SingularityTaskUsage o2) {
return Double.compare(o1.getTimestamp(), o2.getTimestamp());
}
};
public List<SingularityTaskUsage> getTaskUsage(String taskId) {
List<SingularityTaskUsage> children = getAsyncChildren(getTaskUsageHistoryPath(taskId), taskUsageTranscoder);
Collections.sort(children, TASK_USAGE_COMPARATOR_TIMESTAMP_ASC);
return children;
}
public List<SingularitySlaveUsageWithId> getAllCurrentSlaveUsage() {
List<String> slaves = getSlavesWithUsage();
List<String> paths = new ArrayList<>(slaves.size());
for (String slaveId : slaves) {
paths.add(getCurrentSlaveUsagePath(slaveId));
}
Map<String, SingularitySlaveUsage> currentSlaveUsage = getAsyncWithPath("getAllCurrentSlaveUsage", paths, slaveUsageTranscoder);
List<SingularitySlaveUsageWithId> slaveUsageWithIds = new ArrayList<>(currentSlaveUsage.size());
for (Entry<String, SingularitySlaveUsage> entry : currentSlaveUsage.entrySet()) {
slaveUsageWithIds.add(new SingularitySlaveUsageWithId(entry.getValue(), getSlaveIdFromCurrentUsagePath(entry.getKey())));
}
return slaveUsageWithIds;
}
public List<Long> getSlaveUsageTimestamps(String slaveId) {
List<String> timestampStrings = getChildren(getSlaveUsageHistoryPath(slaveId));
List<Long> timestamps = new ArrayList<>(timestampStrings.size());
for (String timestampString : timestampStrings) {
timestamps.add(Long.parseLong(timestampString));
}
Collections.sort(timestamps);
return timestamps;
}
public List<SingularityTaskCurrentUsageWithId> getTaskCurrentUsages(List<SingularityTaskId> taskIds) {
List<String> paths = new ArrayList<>(taskIds.size());
for (SingularityTaskId taskId : taskIds) {
paths.add(getCurrentTaskUsagePath(taskId.getId()));
}
Map<String, SingularityTaskCurrentUsage> currentTaskUsages = getAsyncWithPath("getTaskCurrentUsages", paths, taskCurrentUsageTranscoder);
List<SingularityTaskCurrentUsageWithId> currentTaskUsagesWithIds = new ArrayList<>(paths.size());
for (Entry<String, SingularityTaskCurrentUsage> entry : currentTaskUsages.entrySet()) {
currentTaskUsagesWithIds.add(new SingularityTaskCurrentUsageWithId(SingularityTaskId.valueOf(getTaskIdFromCurrentUsagePath(entry.getKey())), entry.getValue()));
}
return currentTaskUsagesWithIds;
}
}