use of com.yahoo.vespa.applicationmodel.ApplicationInstanceReference in project vespa by vespa-engine.
the class OrchestratorUtilTest method applicationid_conversion_are_symmetric.
/**
* Here we don't care how the internal of the different application
* id/reference look like as long as we get back to exactly where we
* started from a round trip. I.e I'm not testing validity of the
* different representations.
*/
@Test
public void applicationid_conversion_are_symmetric() throws Exception {
// From appId to appRef and back
ApplicationInstanceReference appRef = OrchestratorUtil.toApplicationInstanceReference(APPID_1, new DummyInstanceLookupService());
ApplicationId appIdRoundTrip = OrchestratorUtil.toApplicationId(appRef);
Assert.assertEquals(APPID_1, appIdRoundTrip);
// From appRef to appId and back
ApplicationId appId = OrchestratorUtil.toApplicationId(APPREF_1);
ApplicationInstanceReference appRefRoundTrip = OrchestratorUtil.toApplicationInstanceReference(appId, new DummyInstanceLookupService());
Assert.assertEquals(APPREF_1, appRefRoundTrip);
}
use of com.yahoo.vespa.applicationmodel.ApplicationInstanceReference in project vespa by vespa-engine.
the class OrchestratorImpl method suspendGroup.
// Public for testing purposes
@Override
public void suspendGroup(NodeGroup nodeGroup) throws HostStateChangeDeniedException, HostNameNotFoundException {
ApplicationInstanceReference applicationReference = nodeGroup.getApplicationReference();
try (MutableStatusRegistry hostStatusRegistry = statusService.lockApplicationInstance_forCurrentThreadOnly(applicationReference)) {
ApplicationInstanceStatus appStatus = statusService.forApplicationInstance(applicationReference).getApplicationInstanceStatus();
if (appStatus == ApplicationInstanceStatus.ALLOWED_TO_BE_DOWN) {
return;
}
ApplicationApi applicationApi = new ApplicationApiImpl(nodeGroup, hostStatusRegistry, clusterControllerClientFactory);
policy.grantSuspensionRequest(applicationApi);
}
}
use of com.yahoo.vespa.applicationmodel.ApplicationInstanceReference in project vespa by vespa-engine.
the class OrchestratorImpl method compareNodeGroupsForSuspend.
private static int compareNodeGroupsForSuspend(NodeGroup leftNodeGroup, NodeGroup rightNodeGroup) {
ApplicationInstanceReference leftApplicationReference = leftNodeGroup.getApplicationReference();
ApplicationInstanceReference rightApplicationReference = rightNodeGroup.getApplicationReference();
// ApplicationInstanceReference.toString() is e.g. "hosted-vespa:routing:dev:some-region:default"
return leftApplicationReference.asString().compareTo(rightApplicationReference.asString());
}
use of com.yahoo.vespa.applicationmodel.ApplicationInstanceReference in project vespa by vespa-engine.
the class OrchestratorImpl method setApplicationStatus.
private void setApplicationStatus(ApplicationId appId, ApplicationInstanceStatus status) throws ApplicationStateChangeDeniedException, ApplicationIdNotFoundException {
ApplicationInstanceReference appRef = OrchestratorUtil.toApplicationInstanceReference(appId, instanceLookupService);
try (MutableStatusRegistry statusRegistry = statusService.lockApplicationInstance_forCurrentThreadOnly(appRef)) {
// Short-circuit if already in wanted state
if (status == statusRegistry.getApplicationInstanceStatus())
return;
// Set content clusters for this application in maintenance on suspend
if (status == ApplicationInstanceStatus.ALLOWED_TO_BE_DOWN) {
ApplicationInstance application = getApplicationInstance(appRef);
// Mark it allowed to be down before we manipulate the clustercontroller
OrchestratorUtil.getHostsUsedByApplicationInstance(application).forEach(h -> statusRegistry.setHostState(h, HostStatus.ALLOWED_TO_BE_DOWN));
// If the clustercontroller throws an error the nodes will be marked as allowed to be down
// and be set back up on next resume invocation.
setClusterStateInController(application, ClusterControllerNodeState.MAINTENANCE);
}
statusRegistry.setApplicationInstanceStatus(status);
}
}
use of com.yahoo.vespa.applicationmodel.ApplicationInstanceReference in project vespa by vespa-engine.
the class OrchestratorImpl method nodeGroupsOrderedForSuspend.
/**
* PROBLEM
* Take the example of 2 Docker hosts:
* - Docker host 1 has two nodes A1 and B1, belonging to the application with
* a globally unique ID A and B, respectively.
* - Similarly, Docker host 2 has two nodes running content nodes A2 and B2,
* and we assume both A1 and A2 (and B1 and B2) have services within the same service cluster.
*
* Suppose both Docker hosts wanting to reboot, and
* - Docker host 1 asks to suspend A1 and B1, while
* - Docker host 2 asks to suspend B2 and A2.
*
* The Orchestrator may allow suspend of A1 and B2, before requesting the suspension of B1 and A2.
* None of these can be suspended (assuming max 1 suspended content node per content cluster),
* and so both requests for suspension will fail.
*
* Note that it's not a deadlock - both client will fail immediately and resume both A1 and B2 before
* responding to the client, and if host 1 asks later w/o host 2 asking at the same time,
* it will be given permission to suspend. However if both hosts were to request in lock-step,
* there would be starvation. And in general, it would fail requests for suspension more
* than necessary.
*
* SOLUTION
* The solution we're using is to order the hostnames by the globally unique application instance ID,
* e.g. hosted-vespa:routing:dev:some-region:default. In the example above, it would guarantee
* Docker host 2 would ensure ask to suspend B2 before A2. We take care of that ordering here.
*
* NodeGroups complicate the above picture a little: Each A1, A2, B1, and B2 is a NodeGroup that may
* contain several nodes (on the same Docker host). But the argument still applies.
*/
private List<NodeGroup> nodeGroupsOrderedForSuspend(List<HostName> hostNames) throws HostNameNotFoundException {
Map<ApplicationInstanceReference, NodeGroup> nodeGroupMap = new HashMap<>(hostNames.size());
for (HostName hostName : hostNames) {
ApplicationInstance application = getApplicationInstance(hostName);
NodeGroup nodeGroup = nodeGroupMap.get(application.reference());
if (nodeGroup == null) {
nodeGroup = new NodeGroup(application);
nodeGroupMap.put(application.reference(), nodeGroup);
}
nodeGroup.addNode(hostName);
}
return nodeGroupMap.values().stream().sorted(OrchestratorImpl::compareNodeGroupsForSuspend).collect(Collectors.toList());
}
Aggregations