use of net.dempsy.intern.ApplicationState in project Dempsy by Dempsy.
the class OutgoingDispatcher method dispatch.
@Override
public void dispatch(final KeyedMessageWithType message) {
boolean messageSentSomewhere = false;
try {
ApplicationState tmp = outbounds.get();
// if we're in the midst of an update then we really want to wait for the new state.
while (tmp == null) {
if (!isRunning.get()) {
LOGGER.debug("Router dispatch called while stopped.");
return;
}
if (// however, if we never were ready then we're not in the midst
!isReady.get())
// of an update.
throw new IllegalStateException("Dispatch used before Router is ready.");
// let the other threads do their thing. Maybe we'll be updated sooner.
Thread.yield();
// are we updated yet?
tmp = outbounds.get();
}
final ApplicationState cur = tmp;
final Map<String, RoutingStrategy.Router[]> outboundsByMessageType = cur.outboundsByMessageType;
// =================================================================================
// For each message type, determine the set of Routers. The goal of this loop is to set
// 'containerByNodeAddress'
final Map<NodeAddress, ContainerAddress> containerByNodeAddress = new HashMap<>();
for (final String mt : message.messageTypes) {
final RoutingStrategy.Router[] routers = outboundsByMessageType.get(mt);
if (routers == null)
LOGGER.trace("No cluster that handles messages of type {}", mt);
else {
// the set of ContainerAddresses that this message will be sent to.
for (int i = 0; i < routers.length; i++) {
final ContainerAddress ca = routers[i].selectDestinationForMessage(message);
// it's possible 'ca' is null when we don't know where to send the message.
if (ca == null)
LOGGER.debug("No way to send the message {} to specific cluster for the time being", message.message);
else {
// When the message will be sent to 2 different clusters, but both clusters
// are hosted in the same node, then we send 1 message to 1 ContainerAddress
// where the 'clusters' field contains both container ids.
final ContainerAddress already = containerByNodeAddress.get(ca.node);
if (already != null) {
final int[] ia = new int[already.clusters.length + ca.clusters.length];
System.arraycopy(already.clusters, 0, ia, 0, already.clusters.length);
System.arraycopy(ca.clusters, 0, ia, already.clusters.length, ca.clusters.length);
containerByNodeAddress.put(ca.node, new ContainerAddress(ca.node, ia));
} else
containerByNodeAddress.put(ca.node, ca);
}
}
}
}
for (final Map.Entry<NodeAddress, ContainerAddress> e : containerByNodeAddress.entrySet()) {
final NodeAddress curNode = e.getKey();
final ContainerAddress curAddr = e.getValue();
final RoutedMessage toSend = new RoutedMessage(curAddr.clusters, message.key, message.message);
if (curNode.equals(thisNode)) {
// this shouldn't count since Router is an OUTGOING class
nodeReciever.feedbackLoop(toSend, false);
messageSentSomewhere = true;
} else {
final Sender sender = cur.getSender(curNode);
if (sender == null) {
// router update is probably behind the routing strategy update
if (isRunning.get())
LOGGER.error("Couldn't send message to " + curNode + " from " + thisNodeId + " because there's no " + Sender.class.getSimpleName());
} else {
sender.send(toSend);
messageSentSomewhere = true;
}
}
}
if (containerByNodeAddress.size() == 0) {
if (LOGGER.isTraceEnabled())
LOGGER.trace("There appears to be no valid destination addresses for the message {}", SafeString.objectDescription(message.message));
}
} finally {
if (!messageSentSomewhere)
statsCollector.messageNotSent();
}
}
use of net.dempsy.intern.ApplicationState in project Dempsy by Dempsy.
the class OutgoingDispatcher method start.
@Override
public void start(final Infrastructure infra) {
final ClusterInfoSession session = infra.getCollaborator();
final String nodesDir = infra.getRootPaths().nodesDir;
checkup = new PersistentTask(LOGGER, isRunning, infra.getScheduler(), RETRY_TIMEOUT) {
@Override
public boolean execute() {
try {
// collect up all NodeInfo's known about.
session.recursiveMkdir(nodesDir, null, DirMode.PERSISTENT, DirMode.PERSISTENT);
final Collection<String> nodeDirs = session.getSubdirs(nodesDir, this);
final Set<NodeInformation> alreadySeen = new HashSet<>();
// get all of the subdirectories NodeInformations
for (final String subdir : nodeDirs) {
final NodeInformation ni = (NodeInformation) session.getData(nodesDir + "/" + subdir, null);
if (ni == null) {
LOGGER.warn("A node directory was empty at " + subdir);
return false;
}
// see if node info is dupped.
if (alreadySeen.contains(ni)) {
LOGGER.warn("The node " + ni.nodeAddress + " seems to be registed more than once.");
continue;
}
if (ni.clusterInfoByClusterId.size() == 0) {
// it's ALL adaptor so there's no sense in dealing with it
LOGGER.trace("NodeInformation {} appears to be only an Adaptor.", ni);
continue;
}
alreadySeen.add(ni);
}
// check to see if there's new nodes.
final ApplicationState.Update ud = outbounds.get().update(alreadySeen, thisNode, thisNodeId);
if (!ud.change()) {
isReady.set(true);
// nothing to update.
return true;
} else if (LOGGER.isTraceEnabled())
LOGGER.trace("Updating for " + thisNodeId);
// otherwise we will be making changes so remove the current ApplicationState
// this can cause instability.
final ApplicationState obs = outbounds.getAndSet(null);
try {
final ApplicationState newState = obs.apply(ud, tmanager, statsCollector, manager);
outbounds.set(newState);
isReady.set(true);
return true;
} catch (final RuntimeException rte) {
// if we threw an exception after clearing the outbounds we need to restore it.
// This is likely a configuration error so we should probably warn about it.
LOGGER.warn("Unexpected exception while applying a topology update", rte);
outbounds.set(obs);
throw rte;
}
} catch (final ClusterInfoException e) {
final String message = "Failed to find outgoing route information. Will retry shortly.";
if (LOGGER.isTraceEnabled())
LOGGER.debug(message, e);
else
LOGGER.debug(message);
return false;
}
}
@Override
public String toString() {
return "find nodes to route to";
}
};
outbounds.set(new ApplicationState(tmanager, thisNode));
isRunning.set(true);
checkup.process();
}
use of net.dempsy.intern.ApplicationState in project Dempsy by Dempsy.
the class OutgoingDispatcher method stop.
@Override
public void stop() {
synchronized (isRunning) {
isRunning.set(false);
final ApplicationState cur = outbounds.getAndSet(null);
if (cur != null)
cur.stop();
}
}
Aggregations