}
return;
}
HelixManager manager = changeContext.getManager();
HelixDataAccessor accessor = manager.getHelixDataAccessor();
Builder keyBuilder = accessor.keyBuilder();
if (messages == null || messages.size() == 0)
{
logger.info("No Messages to process");
return;
}
// Sort message based on creation timestamp
Collections.sort(messages, new Comparator<Message>()
{
@Override
public int compare(Message m1, Message m2)
{
return (int) (m1.getCreateTimeStamp() - m2.getCreateTimeStamp());
}
});
List<Message> readMsgs = new ArrayList<Message>();
List<PropertyKey> readMsgKeys = new ArrayList<PropertyKey>();
String sessionId = manager.getSessionId();
List<String> curResourceNames =
accessor.getChildNames(keyBuilder.currentStates(instanceName, sessionId));
List<PropertyKey> createCurStateKeys = new ArrayList<PropertyKey>();
List<CurrentState> metaCurStates = new ArrayList<CurrentState>();
Set<String> createCurStateNames = new HashSet<String>();
// parallel lists that contains handler and the corresponding message
List<MessageHandler> handlers = new ArrayList<MessageHandler>();
List<Message> handleMessages = new ArrayList<Message>();
for (Message message : messages)
{
// NO_OP messages are removed with nothing done. It is used to trigger the
// onMessage() call if needed.
if (message.getMsgType().equalsIgnoreCase(MessageType.NO_OP.toString()))
{
logger.info("Dropping NO-OP msg from " + message.getMsgSrc());
if (message.getTgtName().equalsIgnoreCase("controller"))
{
accessor.removeProperty(keyBuilder.controllerMessage(message.getId()));
}
else
{
accessor.removeProperty(keyBuilder.message(instanceName, message.getId()));
}
continue;
}
String tgtSessionId = message.getTgtSessionId();
if (sessionId.equals(tgtSessionId) || tgtSessionId.equals("*"))
{
if (MessageState.NEW == message.getMsgState())
{
// create message handlers, if handlers not found, don't mark it as READ
try
{
if (!message.getGroupMessageMode())
{
logger.info("Creating handler for message " + message.getMsgId() + "/"
+ message.getPartitionName());
MessageHandler handler = createMessageHandler(message, changeContext);
// We did not find a MessageHandlerFactory for the message;
// we will keep the message and we may be able to handler it when
// the corresponding MessageHandlerFactory factory is registered.
if (handler == null)
{
logger.warn("Message handler factory not found for message type:"
+ message.getMsgType() + ", message:" + message);
continue;
}
handlers.add(handler);
handleMessages.add(message);
}
else
{
List<String> partitionNames = message.getPartitionNames();
AtomicInteger countDown = new AtomicInteger(partitionNames.size());
for (String partitionName : partitionNames)
{
Message msg = new Message(message.getRecord());
msg.setPartitionName(partitionName);
msg.setGroupMsgCountDown(countDown);
logger.info("Creating handler for group message " + msg.getMsgId() + "/"
+ partitionName);
MessageHandler handler = createMessageHandler(msg, changeContext);
// We did not find a MessageHandlerFactory for the message;
// we will keep the message and we may be able to handler it when
// the corresponding MessageHandlerFactory factory is registered.
if (handler == null)
{
logger.warn("Message handler factory not found for group message type:"
+ msg.getMsgType() + ", message:" + msg);
continue;
}
handlers.add(handler);
handleMessages.add(msg);
}
}
}
catch (Exception e)
{
logger.error("Failed to create message handler for " + message.getMsgId(), e);
String error =
"Failed to create message handler for " + message.getMsgId()
+ " exception: " + e;
_statusUpdateUtil.logError(message,
HelixStateMachineEngine.class,
e,
error,
accessor);
// Mark the message as UNPROCESSABLE if we hit a exception while creating
// handler for it. The message will stay on ZK and not be processed.
message.setMsgState(MessageState.UNPROCESSABLE);
if (message.getTgtName().equalsIgnoreCase("controller"))
{
accessor.updateProperty(keyBuilder.controllerMessage(message.getId()),
message);
}
else
{
accessor.updateProperty(keyBuilder.message(instanceName, message.getId()),
message);
}
continue;
}
// update msgState to read
message.setMsgState(MessageState.READ);
message.setReadTimeStamp(new Date().getTime());
message.setExecuteSessionId(changeContext.getManager().getSessionId());
_statusUpdateUtil.logInfo(message,
HelixStateMachineEngine.class,
"New Message",
accessor);
// batch all messages
readMsgs.add(message);
if (message.getTgtName().equalsIgnoreCase("controller"))
{
readMsgKeys.add(keyBuilder.controllerMessage(message.getMsgId()));
}
else
{
// batch all creation of current state meta data
// do it for state transition messages only
if (message.getMsgType()
.equals(Message.MessageType.STATE_TRANSITION.toString()))
{
String resourceName = message.getResourceName();
if (!curResourceNames.contains(resourceName)
&& !createCurStateNames.contains(resourceName))
{
createCurStateNames.add(resourceName);
createCurStateKeys.add(keyBuilder.currentState(instanceName,
sessionId,
resourceName));
CurrentState metaCurState = new CurrentState(resourceName);
metaCurState.setBucketSize(message.getBucketSize());
metaCurState.setStateModelDefRef(message.getStateModelDef());
metaCurState.setSessionId(sessionId);
metaCurState.setGroupMessageMode(message.getGroupMessageMode());
String ftyName = message.getStateModelFactoryName();
if (ftyName != null)
{
metaCurState.setStateModelFactoryName(ftyName);
}
else
{
metaCurState.setStateModelFactoryName(HelixConstants.DEFAULT_STATE_MODEL_FACTORY);
}
metaCurStates.add(metaCurState);
}
}
readMsgKeys.add(keyBuilder.message(instanceName, message.getMsgId()));
}
}
else
{
// This will happen because we don't delete the message as soon as we
// read it.
// We keep it until the current state is changed.
// We will read the message again if there is a new message but we
// check for the status and ignore if its already read
logger.trace("Message already read" + message.getMsgId());
// _statusUpdateUtil.logInfo(message, StateMachineEngine.class,
// "Message already read", client);
}
}
else
{
String warningMessage =
"Session Id does not match. Expected sessionId: " + sessionId
+ ", sessionId from Message: " + tgtSessionId + ". MessageId: "
+ message.getMsgId();
logger.warn(warningMessage);
accessor.removeProperty(keyBuilder.message(instanceName, message.getId()));
_statusUpdateUtil.logWarning(message,
HelixStateMachineEngine.class,
warningMessage,
accessor);
}
}
// batch create curState meta
if (createCurStateKeys.size() > 0)
{
try
{
accessor.createChildren(createCurStateKeys, metaCurStates);
}
catch (Exception e)
{
logger.error(e);
}
}
// update messages in batch and schedule all read messages
if (readMsgs.size() > 0)
{
accessor.setChildren(readMsgKeys, readMsgs);
for (int i = 0; i < handlers.size(); i++)
{
MessageHandler handler = handlers.get(i);
Message handleMessage = handleMessages.get(i);