Search in sources :

Example 1 with ApplicationState

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();
    }
}
Also used : HashMap(java.util.HashMap) ApplicationState(net.dempsy.intern.ApplicationState) RoutedMessage(net.dempsy.transport.RoutedMessage) SafeString(net.dempsy.util.SafeString) ContainerAddress(net.dempsy.router.RoutingStrategy.ContainerAddress) Sender(net.dempsy.transport.Sender) RoutingStrategy(net.dempsy.router.RoutingStrategy) NodeAddress(net.dempsy.transport.NodeAddress) HashMap(java.util.HashMap) Map(java.util.Map)

Example 2 with ApplicationState

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();
}
Also used : HashSet(java.util.HashSet) Set(java.util.Set) ApplicationState(net.dempsy.intern.ApplicationState) ClusterInfoException(net.dempsy.cluster.ClusterInfoException) Collection(java.util.Collection) ClusterInfoSession(net.dempsy.cluster.ClusterInfoSession) SafeString(net.dempsy.util.SafeString) PersistentTask(net.dempsy.utils.PersistentTask)

Example 3 with ApplicationState

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();
    }
}
Also used : ApplicationState(net.dempsy.intern.ApplicationState)

Aggregations

ApplicationState (net.dempsy.intern.ApplicationState)3 SafeString (net.dempsy.util.SafeString)2 Collection (java.util.Collection)1 HashMap (java.util.HashMap)1 HashSet (java.util.HashSet)1 Map (java.util.Map)1 Set (java.util.Set)1 ClusterInfoException (net.dempsy.cluster.ClusterInfoException)1 ClusterInfoSession (net.dempsy.cluster.ClusterInfoSession)1 RoutingStrategy (net.dempsy.router.RoutingStrategy)1 ContainerAddress (net.dempsy.router.RoutingStrategy.ContainerAddress)1 NodeAddress (net.dempsy.transport.NodeAddress)1 RoutedMessage (net.dempsy.transport.RoutedMessage)1 Sender (net.dempsy.transport.Sender)1 PersistentTask (net.dempsy.utils.PersistentTask)1