@Override public boolean verify() throws Exception { ClusterAccessor clusterAccessor = new ClusterAccessor(ClusterId.from(_clusterName), _accessor); Cluster cluster = clusterAccessor.readCluster(); List<ParticipantId> liveInstances = new ArrayList<ParticipantId>(); liveInstances.addAll(cluster.getLiveParticipantMap().keySet()); boolean success = verifyLiveNodes(liveInstances); if (!success) { LOG.info( "liveNodes not match, expect: " + _expectSortedLiveNodes + ", actual: " + liveInstances); return false; } BestPossibleStateOutput bestPossbileStates = calculateBestPossibleState(cluster); Map<String, ExternalView> externalViews = _accessor.getChildValuesMap(_keyBuilder.externalViews()); // TODO all ideal-states should be included in external-views for (String resourceName : externalViews.keySet()) { ExternalView externalView = externalViews.get(resourceName); ResourceAssignment assignment = bestPossbileStates.getResourceAssignment(ResourceId.from(resourceName)); final Map<PartitionId, Map<String, String>> bestPossibleState = Maps.newHashMap(); for (PartitionId partitionId : assignment.getMappedPartitionIds()) { Map<String, String> rawStateMap = ResourceAssignment.stringMapFromReplicaMap(assignment.getReplicaMap(partitionId)); bestPossibleState.put(partitionId, rawStateMap); } success = verifyExternalView(externalView, bestPossibleState); if (!success) { LOG.info("external-view for resource: " + resourceName + " not match"); return false; } } return true; }
/** * TODO: This code is duplicate in multiple places. Can we do it in to one place in the beginning * and compute the stateConstraint instance once and re use at other places. Each IdealState must * have a constraint object associated with it * * @param stateModelDefinition * @param rebalancerConfig if rebalancerConfig == null, we can't evaluate R thus no constraints * @param cluster * @return */ private Map<State, Bounds> computeStateConstraints( StateModelDefinition stateModelDefinition, IdealState idealState, Cluster cluster) { Map<State, Bounds> stateConstraints = new HashMap<State, Bounds>(); List<State> statePriorityList = stateModelDefinition.getTypedStatesPriorityList(); for (State state : statePriorityList) { String numInstancesPerState = stateModelDefinition.getNumParticipantsPerState(state); int max = -1; if ("N".equals(numInstancesPerState)) { max = cluster.getLiveParticipantMap().size(); } else if ("R".equals(numInstancesPerState)) { // idealState is null when resource has been dropped, // R can't be evaluated and ignore state constraints if (idealState != null) { String replicas = idealState.getReplicas(); if (replicas.equals(StateModelToken.ANY_LIVEINSTANCE.toString())) { max = cluster.getLiveParticipantMap().size(); } else { max = Integer.parseInt(replicas); } } } else { try { max = Integer.parseInt(numInstancesPerState); } catch (Exception e) { // use -1 } } if (max > -1) { // if state has no constraint, will not put in map stateConstraints.put(state, new Bounds(0, max)); } } return stateConstraints; }
@Override public void process(ClusterEvent event) throws Exception { Cluster cluster = event.getAttribute("Cluster"); Map<StateModelDefId, StateModelDefinition> stateModelDefMap = cluster.getStateModelMap(); Map<ResourceId, ResourceConfig> resourceMap = event.getAttribute(AttributeName.RESOURCES.toString()); ResourceCurrentState currentStateOutput = event.getAttribute(AttributeName.CURRENT_STATE.toString()); BestPossibleStateOutput bestPossibleStateOutput = event.getAttribute(AttributeName.BEST_POSSIBLE_STATE.toString()); MessageOutput messageGenOutput = event.getAttribute(AttributeName.MESSAGES_ALL.toString()); if (cluster == null || resourceMap == null || currentStateOutput == null || messageGenOutput == null || bestPossibleStateOutput == null) { throw new StageException( "Missing attributes in event:" + event + ". Requires Cluster|RESOURCES|CURRENT_STATE|BEST_POSSIBLE_STATE|MESSAGES_ALL"); } MessageOutput output = new MessageOutput(); for (ResourceId resourceId : resourceMap.keySet()) { ResourceConfig resource = resourceMap.get(resourceId); StateModelDefinition stateModelDef = stateModelDefMap.get(resource.getIdealState().getStateModelDefId()); if (stateModelDef == null) { LOG.info( "resource: " + resourceId + " doesn't have state-model-def; e.g. we add a resource config but not add the resource in ideal-states"); continue; } // TODO have a logical model for transition Map<String, Integer> stateTransitionPriorities = getStateTransitionPriorityMap(stateModelDef); Resource configResource = cluster.getResource(resourceId); // if configResource == null, the resource has been dropped Map<State, Bounds> stateConstraints = computeStateConstraints( stateModelDef, configResource == null ? null : configResource.getIdealState(), cluster); // TODO fix it for (PartitionId partitionId : bestPossibleStateOutput.getResourceAssignment(resourceId).getMappedPartitionIds()) { List<Message> messages = messageGenOutput.getMessages(resourceId, partitionId); List<Message> selectedMessages = selectMessages( cluster.getLiveParticipantMap(), currentStateOutput.getCurrentStateMap(resourceId, partitionId), currentStateOutput.getPendingStateMap(resourceId, partitionId), messages, stateConstraints, stateTransitionPriorities, stateModelDef.getTypedInitialState()); output.setMessages(resourceId, partitionId, selectedMessages); } } event.addAttribute(AttributeName.MESSAGES_SELECTED.toString(), output); }