// The target provider is given the state of container and asked for its new state. For each
// state there is a corresponding handler function.
// TargetProvider should be stateless, given the state of cluster and existing participants
// it should return the same result
final TargetProviderResponse response =
targetProvider.evaluateExistingContainers(cluster, resourceId, participants);
// allocate new containers
for (final ContainerSpec spec : response.getContainersToAcquire()) {
final ParticipantId participantId = spec.getParticipantId();
if (!cluster.getParticipantMap().containsKey(participantId)) {
// create a new Participant, attach the container spec
InstanceConfig instanceConfig = new InstanceConfig(participantId);
instanceConfig.setInstanceEnabled(false);
instanceConfig.setContainerSpec(spec);
// create a helix_participant in ACQUIRING state
instanceConfig.setContainerState(ContainerState.ACQUIRING);
// create the helix participant and add it to cluster
helixAdmin.addInstance(cluster.getId().toString(), instanceConfig);
cache.requireFullRefresh();
}
LOG.info("Allocating container for " + participantId);
ListenableFuture<ContainerId> future = containerProvider.allocateContainer(spec);
FutureCallback<ContainerId> callback = new FutureCallback<ContainerId>() {
@Override
public void onSuccess(ContainerId containerId) {
LOG.info("Container " + containerId + " acquired. Marking " + participantId);
updateContainerState(cache, accessor, keyBuilder, cluster, containerId,
participantId, ContainerState.ACQUIRED);
}
@Override
public void onFailure(Throwable t) {
LOG.error("Could not allocate a container for participant " + participantId, t);
updateContainerState(cache, accessor, keyBuilder, cluster, null, participantId,
ContainerState.FAILED);
}
};
safeAddCallback(future, callback);
}
// start new containers
for (final Participant participant : response.getContainersToStart()) {
final ContainerId containerId = participant.getInstanceConfig().getContainerId();
updateContainerState(cache, accessor, keyBuilder, cluster, null, participant.getId(),
ContainerState.CONNECTING);
// create the helix participant and add it to cluster
LOG.info("Starting container " + containerId + " for " + participant.getId());
ListenableFuture<Boolean> future =
containerProvider.startContainer(containerId, participant);
FutureCallback<Boolean> callback = new FutureCallback<Boolean>() {
@Override
public void onSuccess(Boolean result) {
// Do nothing yet, need to wait for live instance
LOG.info("Container " + containerId + " started for " + participant.getId());
}
@Override
public void onFailure(Throwable t) {
LOG.error("Could not start container" + containerId + "for participant "
+ participant.getId(), t);
updateContainerState(cache, accessor, keyBuilder, cluster, null, participant.getId(),
ContainerState.FAILED);
}
};
safeAddCallback(future, callback);
}
// release containers
for (final Participant participant : response.getContainersToRelease()) {
// mark it as finalizing
final ContainerId containerId = participant.getInstanceConfig().getContainerId();
updateContainerState(cache, accessor, keyBuilder, cluster, null, participant.getId(),
ContainerState.FINALIZING);
// remove the participant
LOG.info("Deallocating container " + containerId + " for " + participant.getId());
ListenableFuture<Boolean> future = containerProvider.deallocateContainer(containerId);
FutureCallback<Boolean> callback = new FutureCallback<Boolean>() {
@Override
public void onSuccess(Boolean result) {
LOG.info("Container " + containerId + " deallocated. Dropping " + participant.getId());
InstanceConfig existingInstance =
helixAdmin.getInstanceConfig(cluster.getId().toString(), participant.getId()
.toString());
helixAdmin.dropInstance(cluster.getId().toString(), existingInstance);
cache.requireFullRefresh();
}
@Override
public void onFailure(Throwable t) {
LOG.error("Could not deallocate container" + containerId + "for participant "
+ participant.getId(), t);
updateContainerState(cache, accessor, keyBuilder, cluster, null, participant.getId(),
ContainerState.FAILED);
}
};
safeAddCallback(future, callback);
}
// stop but don't remove
for (final Participant participant : response.getContainersToStop()) {
// switch to halting
final ContainerId containerId = participant.getInstanceConfig().getContainerId();
updateContainerState(cache, accessor, keyBuilder, cluster, null, participant.getId(),
ContainerState.HALTING);
// stop the container