Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.hubspot.singularity.data.AbstractMachineManager Maven / Gradle / Ivy
package com.hubspot.singularity.data;
import com.codahale.metrics.MetricRegistry;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.hubspot.singularity.MachineState;
import com.hubspot.singularity.SingularityCreateResult;
import com.hubspot.singularity.SingularityDeleteResult;
import com.hubspot.singularity.SingularityMachineAbstraction;
import com.hubspot.singularity.SingularityMachineStateHistoryUpdate;
import com.hubspot.singularity.config.SingularityConfiguration;
import com.hubspot.singularity.data.transcoders.Transcoder;
import com.hubspot.singularity.expiring.SingularityExpiringMachineState;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.utils.ZKPaths;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public abstract class AbstractMachineManager>
extends CuratorAsyncManager {
private static final Logger LOG = LoggerFactory.getLogger(AbstractMachineManager.class);
private static final String HISTORY_PATH = "history";
private static final String EXPIRING_PATH = "expiring";
private final Transcoder transcoder;
private final Transcoder historyTranscoder;
private final Transcoder expiringMachineStateTranscoder;
private final int maxHistoryEntries;
public AbstractMachineManager(
CuratorFramework curator,
SingularityConfiguration configuration,
MetricRegistry metricRegistry,
Transcoder transcoder,
Transcoder historyTranscoder,
Transcoder expiringMachineStateTranscoder
) {
super(curator, configuration, metricRegistry);
this.transcoder = transcoder;
this.historyTranscoder = historyTranscoder;
this.expiringMachineStateTranscoder = expiringMachineStateTranscoder;
this.maxHistoryEntries = configuration.getMaxMachineHistoryEntries();
}
protected abstract String getRoot();
private String getHistoryPath(String objectId) {
return ZKPaths.makePath(getObjectPath(objectId), HISTORY_PATH);
}
public List getHistory(String objectId) {
return getAsyncChildren(getHistoryPath(objectId), historyTranscoder);
}
public List getObjects() {
List fromCache = getObjectsFromLeaderCache();
if (fromCache != null) {
return fromCache;
} else {
return getObjectsNoCache(getRoot());
}
}
protected abstract List getObjectsFromLeaderCache();
public List getObjectIds() {
return getChildren(getRoot());
}
public int getNumObjectsAtState(MachineState state) {
return getObjectsFiltered(state).size();
}
public int getNumActive() {
return getNumObjectsAtState(MachineState.ACTIVE);
}
public Map getObjectsByIdForState(MachineState state) {
List filteredObjects = getObjectsFiltered(state);
Map filteredObjectIds = Maps.newHashMapWithExpectedSize(
filteredObjects.size()
);
for (T filteredObject : filteredObjects) {
filteredObjectIds.put(filteredObject.getId(), filteredObject);
}
return filteredObjectIds;
}
public List getObjectsFiltered(MachineState state) {
List fromCache = getObjectsFromLeaderCache();
if (fromCache != null) {
return fromCache
.stream()
.filter(o -> o.getCurrentState().getState() == state)
.collect(Collectors.toList());
} else {
return getObjectsFiltered(Optional.of(state));
}
}
public List getObjectsFiltered(Optional state) {
List objects = getObjects();
if (!state.isPresent()) {
return objects;
}
return getObjectsFiltered(objects, state.get());
}
private List getObjectsFiltered(List objects, MachineState state) {
List filtered = Lists.newArrayListWithCapacity(objects.size());
for (T object : objects) {
if (object.getCurrentState().getState() == state) {
filtered.add(object);
}
}
return filtered;
}
private String getObjectPath(String objectId) {
return ZKPaths.makePath(getRoot(), objectId);
}
public Optional getObject(String objectId) {
Optional maybeCached = getObjectFromLeaderCache(objectId);
if (!maybeCached.isPresent()) {
return getObjectNoCache(objectId);
} else {
return maybeCached;
}
}
protected abstract Optional getObjectFromLeaderCache(String objectId);
public Optional getObjectNoCache(String objectId) {
return getData(getObjectPath(objectId), transcoder);
}
protected List getObjectsNoCache(String root) {
return getAsyncChildren(root, transcoder);
}
protected abstract void deleteFromLeaderCache(String objectId);
public enum StateChangeResult {
FAILURE_NOT_FOUND,
FAILURE_ALREADY_AT_STATE,
FAILURE_ILLEGAL_TRANSITION,
SUCCESS
}
public StateChangeResult changeState(
String objectId,
MachineState newState,
Optional message,
Optional user
) {
Optional maybeObject = getObject(objectId);
if (!maybeObject.isPresent()) {
return StateChangeResult.FAILURE_NOT_FOUND;
}
final T object = maybeObject.get();
return changeState(object, newState, message, user);
}
public StateChangeResult changeState(
T object,
MachineState newState,
Optional message,
Optional user
) {
Optional maybeInvalidStateChange = getInvalidStateChangeResult(
object.getCurrentState().getState(),
newState,
false
);
if (maybeInvalidStateChange.isPresent()) {
return maybeInvalidStateChange.get();
}
clearExpiringStateChangeIfInvalid(object, newState);
SingularityMachineStateHistoryUpdate newStateUpdate = new SingularityMachineStateHistoryUpdate(
object.getId(),
newState,
System.currentTimeMillis(),
user,
message
);
LOG.debug(
"{} changing state from {} to {} by {}",
object.getId(),
object.getCurrentState().getState(),
newState,
user
);
saveObject(object.changeState(newStateUpdate));
return StateChangeResult.SUCCESS;
}
private void clearExpiringStateChangeIfInvalid(T object, MachineState newState) {
Optional maybeExpiring = getExpiringObject(
object.getId()
);
if (!maybeExpiring.isPresent()) {
return;
}
MachineState targetExpiringState = maybeExpiring.get().getRevertToState();
Optional maybeInvalidStateChange = getInvalidStateChangeResult(
newState,
targetExpiringState,
true
);
if (maybeInvalidStateChange.isPresent()) {
LOG.info(
"Cannot complete expiring state transition from {} to {}, removing expiring action for {}",
newState,
targetExpiringState,
object.getId()
);
deleteExpiringObject(object.getId());
}
}
private Optional getInvalidStateChangeResult(
MachineState currentState,
MachineState newState,
boolean expiringAction
) {
if (currentState == newState) {
return Optional.of(StateChangeResult.FAILURE_ALREADY_AT_STATE);
}
if (
newState == MachineState.STARTING_DECOMMISSION && currentState.isDecommissioning()
) {
return Optional.of(StateChangeResult.FAILURE_ILLEGAL_TRANSITION);
}
// can't jump from FROZEN or ACTIVE to DECOMMISSIONING or DECOMMISSIONED
if (
(
(newState == MachineState.DECOMMISSIONING) ||
(newState == MachineState.DECOMMISSIONED)
) &&
(currentState == MachineState.FROZEN || currentState == MachineState.ACTIVE)
) {
return Optional.of(StateChangeResult.FAILURE_ILLEGAL_TRANSITION);
}
// can't jump from a decommissioning state to FROZEN
if ((newState == MachineState.FROZEN) && currentState.isDecommissioning()) {
return Optional.of(StateChangeResult.FAILURE_ILLEGAL_TRANSITION);
}
// User/Expiring can't jump from inactive to active state
if (currentState.isInactive() && expiringAction) {
return Optional.of(StateChangeResult.FAILURE_ILLEGAL_TRANSITION);
}
return Optional.empty();
}
private String getHistoryUpdatePath(
SingularityMachineStateHistoryUpdate historyUpdate
) {
final String historyChildPath = String.format(
"%s-%s",
historyUpdate.getState().name(),
historyUpdate.getTimestamp()
);
return ZKPaths.makePath(
getHistoryPath(historyUpdate.getObjectId()),
historyChildPath
);
}
public void clearOldHistory(String machineId) {
List histories = getHistory(machineId);
histories.sort(
Comparator
.comparingLong(SingularityMachineStateHistoryUpdate::getTimestamp)
.reversed()
);
histories
.stream()
.skip(maxHistoryEntries)
.forEach(
history -> {
delete(getHistoryUpdatePath(history));
}
);
}
private SingularityCreateResult saveHistoryUpdate(
SingularityMachineStateHistoryUpdate historyUpdate
) {
return create(getHistoryUpdatePath(historyUpdate), historyUpdate, historyTranscoder);
}
public SingularityDeleteResult deleteObject(String objectId) {
deleteFromLeaderCache(objectId);
return delete(getObjectPath(objectId));
}
public void saveObject(T object) {
saveHistoryUpdate(object.getCurrentState());
save(getObjectPath(object.getId()), object, transcoder);
saveObjectToLeaderCache(object);
}
protected abstract void saveObjectToLeaderCache(T object);
private String getExpiringPath(String machineId) {
return ZKPaths.makePath(getRoot(), EXPIRING_PATH, machineId);
}
public List getExpiringObjects() {
return getAsyncChildren(
ZKPaths.makePath(getRoot(), EXPIRING_PATH),
expiringMachineStateTranscoder
);
}
public Optional getExpiringObject(String machineId) {
return getData(getExpiringPath(machineId), expiringMachineStateTranscoder);
}
public SingularityCreateResult saveExpiringObject(
SingularityExpiringMachineState expiringMachineState,
String machineId
) {
return save(
getExpiringPath(machineId),
expiringMachineState,
expiringMachineStateTranscoder
);
}
public SingularityDeleteResult deleteExpiringObject(String machineId) {
return delete(getExpiringPath(machineId));
}
}