Search in sources :

Example 1 with Resource

use of org.apache.helix.model.Resource in project helix by apache.

the class MessageGenerationPhase method process.

@Override
public void process(ClusterEvent event) throws Exception {
    HelixManager manager = event.getAttribute(AttributeName.helixmanager.name());
    ClusterDataCache cache = event.getAttribute(AttributeName.ClusterDataCache.name());
    Map<String, Resource> resourceMap = event.getAttribute(AttributeName.RESOURCES_TO_REBALANCE.name());
    Map<String, List<Message>> pendingMessagesToCleanUp = new HashMap<>();
    CurrentStateOutput currentStateOutput = event.getAttribute(AttributeName.CURRENT_STATE.name());
    IntermediateStateOutput intermediateStateOutput = event.getAttribute(AttributeName.INTERMEDIATE_STATE.name());
    if (manager == null || cache == null || resourceMap == null || currentStateOutput == null || intermediateStateOutput == null) {
        throw new StageException("Missing attributes in event:" + event + ". Requires HelixManager|DataCache|RESOURCES|CURRENT_STATE|INTERMEDIATE_STATE");
    }
    Map<String, LiveInstance> liveInstances = cache.getLiveInstances();
    Map<String, String> sessionIdMap = new HashMap<String, String>();
    for (LiveInstance liveInstance : liveInstances.values()) {
        sessionIdMap.put(liveInstance.getInstanceName(), liveInstance.getSessionId());
    }
    MessageGenerationOutput output = new MessageGenerationOutput();
    for (String resourceName : resourceMap.keySet()) {
        Resource resource = resourceMap.get(resourceName);
        StateModelDefinition stateModelDef = cache.getStateModelDef(resource.getStateModelDefRef());
        if (stateModelDef == null) {
            logger.error("State Model Definition null, skip generating messages for resource: " + resourceName);
            continue;
        }
        for (Partition partition : resource.getPartitions()) {
            Map<String, String> instanceStateMap = new HashMap<String, String>(intermediateStateOutput.getInstanceStateMap(resourceName, partition));
            Map<String, String> pendingStateMap = currentStateOutput.getPendingStateMap(resourceName, partition);
            for (String instance : pendingStateMap.keySet()) {
                if (!instanceStateMap.containsKey(instance)) {
                    instanceStateMap.put(instance, NO_DESIRED_STATE);
                }
            }
            // we should generate message based on the desired-state priority
            // so keep generated messages in a temp map keyed by state
            // desired-state->list of generated-messages
            Map<String, List<Message>> messageMap = new HashMap<String, List<Message>>();
            for (String instanceName : instanceStateMap.keySet()) {
                String desiredState = instanceStateMap.get(instanceName);
                String currentState = currentStateOutput.getCurrentState(resourceName, partition, instanceName);
                if (currentState == null) {
                    currentState = stateModelDef.getInitialState();
                }
                Message pendingMessage = currentStateOutput.getPendingState(resourceName, partition, instanceName);
                boolean isCancellationEnabled = cache.getClusterConfig().isStateTransitionCancelEnabled();
                Message cancellationMessage = currentStateOutput.getCancellationState(resourceName, partition, instanceName);
                String nextState = stateModelDef.getNextStateForTransition(currentState, desiredState);
                Message message = null;
                if (shouldCleanUpPendingMessage(pendingMessage, currentState, currentStateOutput.getEndTime(resourceName, partition, instanceName))) {
                    logger.info("Adding pending message {} on instance {} to clean up. Msg: {}->{}, current state of resource {}:{} is {}", pendingMessage.getMsgId(), instanceName, pendingMessage.getFromState(), pendingMessage.getToState(), resourceName, partition, currentState);
                    if (!pendingMessagesToCleanUp.containsKey(instanceName)) {
                        pendingMessagesToCleanUp.put(instanceName, new ArrayList<Message>());
                    }
                    pendingMessagesToCleanUp.get(instanceName).add(pendingMessage);
                }
                if (desiredState.equals(NO_DESIRED_STATE) || desiredState.equalsIgnoreCase(currentState)) {
                    if (desiredState.equals(NO_DESIRED_STATE) || pendingMessage != null && !currentState.equalsIgnoreCase(pendingMessage.getToState())) {
                        message = createStateTransitionCancellationMessage(manager, resource, partition.getPartitionName(), instanceName, sessionIdMap.get(instanceName), stateModelDef.getId(), pendingMessage.getFromState(), pendingMessage.getToState(), null, cancellationMessage, isCancellationEnabled, currentState);
                    }
                } else {
                    if (nextState == null) {
                        logger.error("Unable to find a next state for resource: " + resource.getResourceName() + " partition: " + partition.getPartitionName() + " from stateModelDefinition" + stateModelDef.getClass() + " from:" + currentState + " to:" + desiredState);
                        continue;
                    }
                    if (pendingMessage != null) {
                        String pendingState = pendingMessage.getToState();
                        if (nextState.equalsIgnoreCase(pendingState)) {
                            logger.debug("Message already exists for " + instanceName + " to transit " + resource.getResourceName() + "." + partition.getPartitionName() + " from " + currentState + " to " + nextState);
                        } else if (currentState.equalsIgnoreCase(pendingState)) {
                            logger.info("Message hasn't been removed for " + instanceName + " to transit " + resource.getResourceName() + "." + partition.getPartitionName() + " to " + pendingState + ", desiredState: " + desiredState);
                        } else {
                            logger.info("IdealState changed before state transition completes for " + resource.getResourceName() + "." + partition.getPartitionName() + " on " + instanceName + ", pendingState: " + pendingState + ", currentState: " + currentState + ", nextState: " + nextState);
                            message = createStateTransitionCancellationMessage(manager, resource, partition.getPartitionName(), instanceName, sessionIdMap.get(instanceName), stateModelDef.getId(), pendingMessage.getFromState(), pendingState, nextState, cancellationMessage, isCancellationEnabled, currentState);
                        }
                    } else {
                        // Create new state transition message
                        message = createStateTransitionMessage(manager, resource, partition.getPartitionName(), instanceName, currentState, nextState, sessionIdMap.get(instanceName), stateModelDef.getId());
                    }
                }
                if (message != null) {
                    IdealState idealState = cache.getIdealState(resourceName);
                    if (idealState != null && idealState.getStateModelDefRef().equalsIgnoreCase(DefaultSchedulerMessageHandlerFactory.SCHEDULER_TASK_QUEUE)) {
                        if (idealState.getRecord().getMapField(partition.getPartitionName()) != null) {
                            message.getRecord().setMapField(Message.Attributes.INNER_MESSAGE.toString(), idealState.getRecord().getMapField(partition.getPartitionName()));
                        }
                    }
                    int timeout = getTimeOut(cache.getClusterConfig(), cache.getResourceConfig(resourceName), currentState, nextState, idealState, partition);
                    if (timeout > 0) {
                        message.setExecutionTimeout(timeout);
                    }
                    message.setAttribute(Message.Attributes.ClusterEventName, event.getEventType().name());
                    // output.addMessage(resourceName, partition, message);
                    if (!messageMap.containsKey(desiredState)) {
                        messageMap.put(desiredState, new ArrayList<Message>());
                    }
                    messageMap.get(desiredState).add(message);
                }
            }
            // add generated messages to output according to state priority
            List<String> statesPriorityList = stateModelDef.getStatesPriorityList();
            for (String state : statesPriorityList) {
                if (messageMap.containsKey(state)) {
                    for (Message message : messageMap.get(state)) {
                        output.addMessage(resourceName, partition, message);
                    }
                }
            }
        }
    // end of for-each-partition
    }
    // Asynchronously clean up pending messages if necessary
    if (!pendingMessagesToCleanUp.isEmpty()) {
        schedulePendingMessageCleanUp(pendingMessagesToCleanUp, cache.getAsyncTasksThreadPool(), manager.getHelixDataAccessor());
    }
    event.addAttribute(AttributeName.MESSAGES_ALL.name(), output);
}
Also used : Partition(org.apache.helix.model.Partition) HelixManager(org.apache.helix.HelixManager) Message(org.apache.helix.model.Message) HashMap(java.util.HashMap) StageException(org.apache.helix.controller.pipeline.StageException) Resource(org.apache.helix.model.Resource) IdealState(org.apache.helix.model.IdealState) LiveInstance(org.apache.helix.model.LiveInstance) StateModelDefinition(org.apache.helix.model.StateModelDefinition) ArrayList(java.util.ArrayList) List(java.util.List)

Example 2 with Resource

use of org.apache.helix.model.Resource in project helix by apache.

the class MessageSelectionStage method process.

@Override
public void process(ClusterEvent event) throws Exception {
    ClusterDataCache cache = event.getAttribute(AttributeName.ClusterDataCache.name());
    Map<String, Resource> resourceMap = event.getAttribute(AttributeName.RESOURCES.name());
    CurrentStateOutput currentStateOutput = event.getAttribute(AttributeName.CURRENT_STATE.name());
    MessageGenerationOutput messageGenOutput = event.getAttribute(AttributeName.MESSAGES_ALL.name());
    if (cache == null || resourceMap == null || currentStateOutput == null || messageGenOutput == null) {
        throw new StageException("Missing attributes in event:" + event + ". Requires DataCache|RESOURCES|CURRENT_STATE|MESSAGES_ALL");
    }
    MessageSelectionStageOutput output = new MessageSelectionStageOutput();
    for (String resourceName : resourceMap.keySet()) {
        Resource resource = resourceMap.get(resourceName);
        StateModelDefinition stateModelDef = cache.getStateModelDef(resource.getStateModelDefRef());
        Map<String, Integer> stateTransitionPriorities = getStateTransitionPriorityMap(stateModelDef);
        IdealState idealState = cache.getIdealState(resourceName);
        Map<String, Bounds> stateConstraints = computeStateConstraints(stateModelDef, idealState, cache);
        for (Partition partition : resource.getPartitions()) {
            List<Message> messages = messageGenOutput.getMessages(resourceName, partition);
            List<Message> selectedMessages = selectMessages(cache.getLiveInstances(), currentStateOutput.getCurrentStateMap(resourceName, partition), currentStateOutput.getPendingMessageMap(resourceName, partition), messages, stateConstraints, stateTransitionPriorities, stateModelDef, resource.isP2PMessageEnabled());
            output.addMessages(resourceName, partition, selectedMessages);
        }
    }
    event.addAttribute(AttributeName.MESSAGES_SELECTED.name(), output);
}
Also used : Partition(org.apache.helix.model.Partition) Message(org.apache.helix.model.Message) StageException(org.apache.helix.controller.pipeline.StageException) Resource(org.apache.helix.model.Resource) IdealState(org.apache.helix.model.IdealState) StateModelDefinition(org.apache.helix.model.StateModelDefinition)

Example 3 with Resource

use of org.apache.helix.model.Resource in project helix by apache.

the class MessageThrottleStage method process.

@Override
public void process(ClusterEvent event) throws Exception {
    ClusterDataCache cache = event.getAttribute(AttributeName.ClusterDataCache.name());
    MessageSelectionStageOutput msgSelectionOutput = event.getAttribute(AttributeName.MESSAGES_SELECTED.name());
    Map<String, Resource> resourceMap = event.getAttribute(AttributeName.RESOURCES.name());
    if (cache == null || resourceMap == null || msgSelectionOutput == null) {
        throw new StageException("Missing attributes in event: " + event + ". Requires ClusterDataCache|RESOURCES|MESSAGES_SELECTED");
    }
    MessageThrottleStageOutput output = new MessageThrottleStageOutput();
    ClusterConstraints constraint = cache.getConstraint(ConstraintType.MESSAGE_CONSTRAINT);
    Map<String, Integer> throttleCounterMap = new HashMap<String, Integer>();
    if (constraint != null) {
        // go through all pending messages, they should be counted but not throttled
        for (String instance : cache.getLiveInstances().keySet()) {
            throttle(throttleCounterMap, constraint, new ArrayList<Message>(cache.getMessages(instance).values()), false);
        }
    }
    // assume messages should be sorted by state transition priority in messageSelection stage
    for (String resourceName : resourceMap.keySet()) {
        Resource resource = resourceMap.get(resourceName);
        for (Partition partition : resource.getPartitions()) {
            List<Message> messages = msgSelectionOutput.getMessages(resourceName, partition);
            if (constraint != null && messages != null && messages.size() > 0) {
                messages = throttle(throttleCounterMap, constraint, messages, true);
            }
            output.addMessages(resourceName, partition, messages);
        }
    }
    event.addAttribute(AttributeName.MESSAGES_THROTTLE.name(), output);
}
Also used : Partition(org.apache.helix.model.Partition) Message(org.apache.helix.model.Message) HashMap(java.util.HashMap) StageException(org.apache.helix.controller.pipeline.StageException) Resource(org.apache.helix.model.Resource) ClusterConstraints(org.apache.helix.model.ClusterConstraints)

Example 4 with Resource

use of org.apache.helix.model.Resource in project helix by apache.

the class CurrentStateComputationStage method updateCurrentStates.

// update current states in CurrentStateOutput
private void updateCurrentStates(LiveInstance instance, Collection<CurrentState> currentStates, CurrentStateOutput currentStateOutput, Map<String, Resource> resourceMap) {
    String instanceName = instance.getInstanceName();
    String instanceSessionId = instance.getSessionId();
    for (CurrentState currentState : currentStates) {
        if (!instanceSessionId.equals(currentState.getSessionId())) {
            continue;
        }
        String resourceName = currentState.getResourceName();
        String stateModelDefName = currentState.getStateModelDefRef();
        Resource resource = resourceMap.get(resourceName);
        if (resource == null) {
            continue;
        }
        if (stateModelDefName != null) {
            currentStateOutput.setResourceStateModelDef(resourceName, stateModelDefName);
        }
        currentStateOutput.setBucketSize(resourceName, currentState.getBucketSize());
        Map<String, String> partitionStateMap = currentState.getPartitionStateMap();
        for (String partitionName : partitionStateMap.keySet()) {
            Partition partition = resource.getPartition(partitionName);
            if (partition != null) {
                currentStateOutput.setCurrentState(resourceName, partition, instanceName, currentState.getState(partitionName));
                currentStateOutput.setRequestedState(resourceName, partition, instanceName, currentState.getRequestedState(partitionName));
                currentStateOutput.setInfo(resourceName, partition, instanceName, currentState.getInfo(partitionName));
                currentStateOutput.setEndTime(resourceName, partition, instanceName, currentState.getEndTime(partitionName));
            }
        }
    }
}
Also used : Partition(org.apache.helix.model.Partition) CurrentState(org.apache.helix.model.CurrentState) Resource(org.apache.helix.model.Resource)

Example 5 with Resource

use of org.apache.helix.model.Resource in project helix by apache.

the class CurrentStateComputationStage method updatePendingMessages.

// update all pending messages to CurrentStateOutput.
private void updatePendingMessages(LiveInstance instance, Collection<Message> pendingMessages, CurrentStateOutput currentStateOutput, Map<String, Resource> resourceMap) {
    String instanceName = instance.getInstanceName();
    String instanceSessionId = instance.getSessionId();
    // update all pending messages
    for (Message message : pendingMessages) {
        if (!MessageType.STATE_TRANSITION.name().equalsIgnoreCase(message.getMsgType()) && !MessageType.STATE_TRANSITION_CANCELLATION.name().equalsIgnoreCase(message.getMsgType())) {
            continue;
        }
        if (!instanceSessionId.equals(message.getTgtSessionId())) {
            continue;
        }
        String resourceName = message.getResourceName();
        Resource resource = resourceMap.get(resourceName);
        if (resource == null) {
            continue;
        }
        if (!message.getBatchMessageMode()) {
            String partitionName = message.getPartitionName();
            Partition partition = resource.getPartition(partitionName);
            if (partition != null) {
                setMessageState(currentStateOutput, resourceName, partition, instanceName, message);
            } else {
            // log
            }
        } else {
            List<String> partitionNames = message.getPartitionNames();
            if (!partitionNames.isEmpty()) {
                for (String partitionName : partitionNames) {
                    Partition partition = resource.getPartition(partitionName);
                    if (partition != null) {
                        setMessageState(currentStateOutput, resourceName, partition, instanceName, message);
                    } else {
                    // log
                    }
                }
            }
        }
    }
}
Also used : Partition(org.apache.helix.model.Partition) Message(org.apache.helix.model.Message) Resource(org.apache.helix.model.Resource)

Aggregations

Resource (org.apache.helix.model.Resource)35 Partition (org.apache.helix.model.Partition)16 Test (org.testng.annotations.Test)15 HashMap (java.util.HashMap)9 IdealState (org.apache.helix.model.IdealState)9 Message (org.apache.helix.model.Message)9 ArrayList (java.util.ArrayList)7 StageException (org.apache.helix.controller.pipeline.StageException)7 ClusterConfig (org.apache.helix.model.ClusterConfig)7 Date (java.util.Date)6 LiveInstance (org.apache.helix.model.LiveInstance)6 HelixDataAccessor (org.apache.helix.HelixDataAccessor)5 CurrentState (org.apache.helix.model.CurrentState)5 StateModelDefinition (org.apache.helix.model.StateModelDefinition)5 Map (java.util.Map)4 HelixManager (org.apache.helix.HelixManager)4 ZNRecord (org.apache.helix.ZNRecord)4 ClusterDataCache (org.apache.helix.controller.stages.ClusterDataCache)4 CurrentStateOutput (org.apache.helix.controller.stages.CurrentStateOutput)4 List (java.util.List)3