use of org.apache.helix.HelixManager in project helix by apache.
the class PersistAssignmentStage method process.
@Override
public void process(ClusterEvent event) throws Exception {
ClusterDataCache cache = event.getAttribute(AttributeName.ClusterDataCache.name());
ClusterConfig clusterConfig = cache.getClusterConfig();
if (!clusterConfig.isPersistBestPossibleAssignment() && !clusterConfig.isPersistIntermediateAssignment()) {
return;
}
BestPossibleStateOutput bestPossibleAssignment = event.getAttribute(AttributeName.BEST_POSSIBLE_STATE.name());
HelixManager helixManager = event.getAttribute(AttributeName.helixmanager.name());
HelixDataAccessor accessor = helixManager.getHelixDataAccessor();
PropertyKey.Builder keyBuilder = accessor.keyBuilder();
Map<String, Resource> resourceMap = event.getAttribute(AttributeName.RESOURCES.name());
for (String resourceId : bestPossibleAssignment.resourceSet()) {
Resource resource = resourceMap.get(resourceId);
if (resource != null) {
final IdealState idealState = cache.getIdealState(resourceId);
if (idealState == null) {
LOG.warn("IdealState not found for resource " + resourceId);
continue;
}
IdealState.RebalanceMode mode = idealState.getRebalanceMode();
if (!mode.equals(IdealState.RebalanceMode.SEMI_AUTO) && !mode.equals(IdealState.RebalanceMode.FULL_AUTO)) {
// do not persist assignment for resource in neither semi or full auto.
continue;
}
boolean needPersist = false;
if (mode.equals(IdealState.RebalanceMode.FULL_AUTO)) {
// persist preference list in ful-auto mode.
Map<String, List<String>> newLists = bestPossibleAssignment.getPreferenceLists(resourceId);
if (newLists != null && hasPreferenceListChanged(newLists, idealState)) {
idealState.setPreferenceLists(newLists);
needPersist = true;
}
}
PartitionStateMap partitionStateMap = bestPossibleAssignment.getPartitionStateMap(resourceId);
if (clusterConfig.isPersistIntermediateAssignment()) {
IntermediateStateOutput intermediateAssignment = event.getAttribute(AttributeName.INTERMEDIATE_STATE.name());
partitionStateMap = intermediateAssignment.getPartitionStateMap(resourceId);
}
// TODO: temporary solution for Espresso/Dbus backcompatible, should remove this.
Map<Partition, Map<String, String>> assignmentToPersist = convertAssignmentPersisted(resource, idealState, partitionStateMap.getStateMap());
if (assignmentToPersist != null && hasInstanceMapChanged(assignmentToPersist, idealState)) {
for (Partition partition : assignmentToPersist.keySet()) {
Map<String, String> instanceMap = assignmentToPersist.get(partition);
idealState.setInstanceStateMap(partition.getPartitionName(), instanceMap);
}
needPersist = true;
}
if (needPersist) {
// Update instead of set to ensure any intermediate changes that the controller does not update are kept.
accessor.updateProperty(keyBuilder.idealStates(resourceId), new DataUpdater<ZNRecord>() {
@Override
public ZNRecord update(ZNRecord current) {
if (current != null) {
// Overwrite MapFields and ListFields items with the same key.
// Note that default merge will keep old values in the maps or lists unchanged, which is not desired.
current.getMapFields().clear();
current.getMapFields().putAll(idealState.getRecord().getMapFields());
current.getListFields().putAll(idealState.getRecord().getListFields());
}
return current;
}
}, idealState);
}
}
}
}
use of org.apache.helix.HelixManager in project helix by apache.
the class TargetExteralViewCalcStage method process.
@Override
public void process(ClusterEvent event) throws Exception {
ClusterDataCache cache = event.getAttribute(AttributeName.ClusterDataCache.name());
ClusterConfig clusterConfig = cache.getClusterConfig();
if (cache.isTaskCache() || !clusterConfig.isTargetExternalViewEnabled()) {
return;
}
HelixManager helixManager = event.getAttribute(AttributeName.helixmanager.name());
HelixDataAccessor accessor = helixManager.getHelixDataAccessor();
if (!accessor.getBaseDataAccessor().exists(accessor.keyBuilder().targetExternalViews().getPath(), AccessOption.PERSISTENT)) {
accessor.getBaseDataAccessor().create(accessor.keyBuilder().targetExternalViews().getPath(), null, AccessOption.PERSISTENT);
}
BestPossibleStateOutput bestPossibleAssignments = event.getAttribute(AttributeName.BEST_POSSIBLE_STATE.name());
IntermediateStateOutput intermediateAssignments = event.getAttribute(AttributeName.INTERMEDIATE_STATE.name());
Map<String, Resource> resourceMap = event.getAttribute(AttributeName.RESOURCES.name());
List<PropertyKey> keys = new ArrayList<>();
List<ExternalView> targetExternalViews = new ArrayList<>();
for (String resourceName : bestPossibleAssignments.resourceSet()) {
if (cache.getIdealState(resourceName) == null || cache.getIdealState(resourceName).isExternalViewDisabled()) {
continue;
}
Resource resource = resourceMap.get(resourceName);
if (resource != null) {
PartitionStateMap partitionStateMap = intermediateAssignments.getPartitionStateMap(resourceName);
Map<String, Map<String, String>> intermediateAssignment = convertToMapFields(partitionStateMap.getStateMap());
Map<String, List<String>> preferenceLists = bestPossibleAssignments.getPreferenceLists(resourceName);
boolean needPersist = false;
ExternalView targetExternalView = cache.getTargetExternalView(resourceName);
if (targetExternalView == null) {
targetExternalView = new ExternalView(resourceName);
targetExternalView.getRecord().getSimpleFields().putAll(cache.getIdealState(resourceName).getRecord().getSimpleFields());
needPersist = true;
}
if (preferenceLists != null && !targetExternalView.getRecord().getListFields().equals(preferenceLists)) {
targetExternalView.getRecord().setListFields(preferenceLists);
needPersist = true;
}
if (intermediateAssignment != null && !targetExternalView.getRecord().getMapFields().equals(intermediateAssignment)) {
targetExternalView.getRecord().setMapFields(intermediateAssignment);
needPersist = true;
}
if (needPersist) {
keys.add(accessor.keyBuilder().targetExternalView(resourceName));
targetExternalViews.add(targetExternalView);
cache.updateTargetExternalView(resourceName, targetExternalView);
}
}
}
accessor.setChildren(keys, targetExternalViews);
}
use of org.apache.helix.HelixManager in project helix by apache.
the class TaskAssignmentStage method process.
@Override
public void process(ClusterEvent event) throws Exception {
HelixManager manager = event.getAttribute(AttributeName.helixmanager.name());
Map<String, Resource> resourceMap = event.getAttribute(AttributeName.RESOURCES_TO_REBALANCE.name());
MessageThrottleStageOutput messageOutput = event.getAttribute(AttributeName.MESSAGES_THROTTLE.name());
ClusterDataCache cache = event.getAttribute(AttributeName.ClusterDataCache.name());
Map<String, LiveInstance> liveInstanceMap = cache.getLiveInstances();
if (manager == null || resourceMap == null || messageOutput == null || cache == null || liveInstanceMap == null) {
throw new StageException("Missing attributes in event:" + event + ". Requires HelixManager|RESOURCES|MESSAGES_THROTTLE|DataCache|liveInstanceMap");
}
HelixDataAccessor dataAccessor = manager.getHelixDataAccessor();
List<Message> messagesToSend = new ArrayList<Message>();
for (String resourceName : resourceMap.keySet()) {
Resource resource = resourceMap.get(resourceName);
for (Partition partition : resource.getPartitions()) {
List<Message> messages = messageOutput.getMessages(resourceName, partition);
messagesToSend.addAll(messages);
}
}
List<Message> outputMessages = batchMessage(dataAccessor.keyBuilder(), messagesToSend, resourceMap, liveInstanceMap, manager.getProperties());
sendMessages(dataAccessor, outputMessages);
// TODO: Need also count messages from task rebalancer
if (!cache.isTaskCache()) {
ClusterStatusMonitor clusterStatusMonitor = event.getAttribute(AttributeName.clusterStatusMonitor.name());
if (clusterStatusMonitor != null) {
clusterStatusMonitor.increaseMessageReceived(outputMessages);
}
}
long cacheStart = System.currentTimeMillis();
cache.cacheMessages(outputMessages);
long cacheEnd = System.currentTimeMillis();
logger.debug("Caching messages took " + (cacheEnd - cacheStart) + " ms");
}
use of org.apache.helix.HelixManager in project helix by apache.
the class GenericHelixController method handleEvent.
/**
* lock-always: caller always needs to obtain an external lock before call, calls to handleEvent()
* should be serialized
* @param event
*/
protected void handleEvent(ClusterEvent event, ClusterDataCache cache) {
HelixManager manager = event.getAttribute(AttributeName.helixmanager.name());
if (manager == null) {
logger.error("No cluster manager in event:" + event.getEventType());
return;
}
if (!manager.isLeader()) {
logger.error("Cluster manager: " + manager.getInstanceName() + " is not leader for " + manager.getClusterName() + ". Pipeline will not be invoked");
return;
}
// will be excuting in un-paused mode. Which might not be the config in ZK.
if (_paused) {
logger.info("Cluster " + manager.getClusterName() + " is paused. Ignoring the event:" + event.getEventType());
return;
}
NotificationContext context = null;
if (event.getAttribute(AttributeName.changeContext.name()) != null) {
context = event.getAttribute(AttributeName.changeContext.name());
}
if (context != null) {
if (context.getType() == Type.FINALIZE) {
stopRebalancingTimers();
logger.info("Get FINALIZE notification, skip the pipeline. Event :" + event.getEventType());
return;
} else {
// TODO: should be in the initialization of controller.
if (_cache != null) {
checkRebalancingTimer(manager, Collections.EMPTY_LIST, _cache.getClusterConfig());
}
if (_isMonitoring) {
event.addAttribute(AttributeName.clusterStatusMonitor.name(), _clusterStatusMonitor);
}
}
}
// add the cache
event.addAttribute(AttributeName.ClusterDataCache.name(), cache);
List<Pipeline> pipelines = cache.isTaskCache() ? _taskRegistry.getPipelinesForEvent(event.getEventType()) : _registry.getPipelinesForEvent(event.getEventType());
if (pipelines == null || pipelines.size() == 0) {
logger.info("No " + getPipelineType(cache.isTaskCache()) + " pipeline to run for event:" + event.getEventType());
return;
}
logger.info(String.format("START: Invoking %s controller pipeline for cluster %s event: %s", manager.getClusterName(), getPipelineType(cache.isTaskCache()), event.getEventType()));
long startTime = System.currentTimeMillis();
boolean rebalanceFail = false;
for (Pipeline pipeline : pipelines) {
try {
pipeline.handle(event);
pipeline.finish();
} catch (Exception e) {
logger.error("Exception while executing " + getPipelineType(cache.isTaskCache()) + "pipeline: " + pipeline + "for cluster ." + _clusterName + ". Will not continue to next pipeline", e);
if (e instanceof HelixMetaDataAccessException) {
rebalanceFail = true;
// If pipeline failed due to read/write fails to zookeeper, retry the pipeline.
cache.requireFullRefresh();
logger.warn("Rebalance pipeline failed due to read failure from zookeeper, cluster: " + _clusterName);
// only push a retry event when there is no pending event in the corresponding event queue.
if (isEventQueueEmpty(cache.isTaskCache())) {
_continousRebalanceFailureCount++;
long delay = getRetryDelay(_continousRebalanceFailureCount);
if (delay == 0) {
forceRebalance(manager, ClusterEventType.RetryRebalance);
} else {
_asyncTasksThreadPool.schedule(new RebalanceTask(manager, ClusterEventType.RetryRebalance), delay, TimeUnit.MILLISECONDS);
}
logger.info("Retry rebalance pipeline with delay " + delay + "ms for cluster: " + _clusterName);
}
}
_clusterStatusMonitor.reportRebalanceFailure();
break;
}
}
if (!rebalanceFail) {
_continousRebalanceFailureCount = 0;
}
long endTime = System.currentTimeMillis();
logger.info(String.format("END: Invoking %s controller pipeline for event: %s for cluster %s, took %d ms", getPipelineType(cache.isTaskCache()), event.getEventType(), manager.getClusterName(), (endTime - startTime)));
if (!cache.isTaskCache()) {
// report event process durations
NotificationContext notificationContext = event.getAttribute(AttributeName.changeContext.name());
long enqueueTime = event.getCreationTime();
long zkCallbackTime;
StringBuilder sb = new StringBuilder();
if (notificationContext != null) {
zkCallbackTime = notificationContext.getCreationTime();
if (_isMonitoring) {
_clusterStatusMonitor.updateClusterEventDuration(ClusterEventMonitor.PhaseName.Callback.name(), enqueueTime - zkCallbackTime);
}
sb.append(String.format("Callback time for event: " + event.getEventType() + " took: " + (enqueueTime - zkCallbackTime) + " ms\n"));
}
if (_isMonitoring) {
_clusterStatusMonitor.updateClusterEventDuration(ClusterEventMonitor.PhaseName.InQueue.name(), startTime - enqueueTime);
_clusterStatusMonitor.updateClusterEventDuration(ClusterEventMonitor.PhaseName.TotalProcessed.name(), endTime - startTime);
}
sb.append(String.format("InQueue time for event: " + event.getEventType() + " took: " + (startTime - enqueueTime) + " ms\n"));
sb.append(String.format("TotalProcessed time for event: " + event.getEventType() + " took: " + (endTime - startTime) + " ms"));
logger.info(sb.toString());
} else if (_isMonitoring) {
// report workflow status
TaskDriver driver = new TaskDriver(manager);
_clusterStatusMonitor.refreshWorkflowsStatus(driver);
_clusterStatusMonitor.refreshJobsStatus(driver);
}
// If event handling happens before controller deactivate, the process may write unnecessary
// MBeans to monitoring after the monitor is disabled.
// So reset ClusterStatusMonitor according to it's status after all event handling.
// TODO remove this once clusterStatusMonitor blocks any MBean register on isMonitoring = false.
resetClusterStatusMonitor();
}
use of org.apache.helix.HelixManager in project helix by apache.
the class GenericHelixController method checkLiveInstancesObservation.
/**
* Go through the list of liveinstances in the cluster, and add currentstateChange listener and
* Message listeners to them if they are newly added. For current state change, the observation is
* tied to the session id of each live instance.
*/
protected void checkLiveInstancesObservation(List<LiveInstance> liveInstances, NotificationContext changeContext) {
// construct maps for current live-instances
Map<String, LiveInstance> curInstances = new HashMap<>();
Map<String, LiveInstance> curSessions = new HashMap<>();
for (LiveInstance liveInstance : liveInstances) {
curInstances.put(liveInstance.getInstanceName(), liveInstance);
curSessions.put(liveInstance.getSessionId(), liveInstance);
}
// TODO: remove the synchronization here once we move this update into dataCache.
synchronized (_lastSeenInstances) {
Map<String, LiveInstance> lastInstances = _lastSeenInstances.get();
Map<String, LiveInstance> lastSessions = _lastSeenSessions.get();
HelixManager manager = changeContext.getManager();
Builder keyBuilder = new Builder(manager.getClusterName());
if (lastSessions != null) {
for (String session : lastSessions.keySet()) {
if (!curSessions.containsKey(session)) {
// remove current-state listener for expired session
String instanceName = lastSessions.get(session).getInstanceName();
manager.removeListener(keyBuilder.currentStates(instanceName, session), this);
}
}
}
if (lastInstances != null) {
for (String instance : lastInstances.keySet()) {
if (!curInstances.containsKey(instance)) {
// remove message listener for disconnected instances
manager.removeListener(keyBuilder.messages(instance), this);
}
}
}
for (String session : curSessions.keySet()) {
if (lastSessions == null || !lastSessions.containsKey(session)) {
String instanceName = curSessions.get(session).getInstanceName();
try {
// add current-state listeners for new sessions
manager.addCurrentStateChangeListener(this, instanceName, session);
logger.info(manager.getInstanceName() + " added current-state listener for instance: " + instanceName + ", session: " + session + ", listener: " + this);
} catch (Exception e) {
logger.error("Fail to add current state listener for instance: " + instanceName + " with session: " + session, e);
}
}
}
for (String instance : curInstances.keySet()) {
if (lastInstances == null || !lastInstances.containsKey(instance)) {
try {
// add message listeners for new instances
manager.addMessageListener(this, instance);
logger.info(manager.getInstanceName() + " added message listener for " + instance + ", listener: " + this);
} catch (Exception e) {
logger.error("Fail to add message listener for instance: " + instance, e);
}
}
}
// update last-seen
_lastSeenInstances.set(curInstances);
_lastSeenSessions.set(curSessions);
}
}
Aggregations