Search in sources :

Example 1 with Sender

use of net.dempsy.transport.Sender 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 Sender

use of net.dempsy.transport.Sender in project Dempsy by Dempsy.

the class ApplicationState method apply.

public ApplicationState apply(final ApplicationState.Update update, final TransportManager tmanager, final NodeStatsCollector statsCollector, final RoutingStrategyManager manager) {
    // apply toDelete first.
    final Set<NodeAddress> toDelete = update.toDelete;
    if (toDelete.size() > 0) {
        // just clear all senders.
        for (final NodeAddress a : toDelete) {
            final Sender s = senders.get(a);
            if (s != null)
                s.stop();
        }
    }
    final Map<NodeAddress, NodeInformation> newCurrent = new HashMap<>();
    // the one's to carry over.
    final Set<NodeInformation> leaveAlone = update.leaveAlone;
    for (final NodeInformation cur : leaveAlone) {
        newCurrent.put(cur.nodeAddress, cur);
    }
    // add new senders
    final Set<NodeInformation> toAdd = update.toAdd;
    for (final NodeInformation cur : toAdd) {
        newCurrent.put(cur.nodeAddress, cur);
    }
    // now flush out the remaining caches.
    // collapse all clusterInfos
    final Set<ClusterInformation> allCis = new HashSet<>();
    newCurrent.values().forEach(ni -> allCis.addAll(ni.clusterInfoByClusterId.values()));
    final Map<String, RoutingStrategy.Router> newOutboundByClusterName = new HashMap<>();
    final Map<String, Set<String>> cnByType = new HashMap<>();
    final Set<String> knownClusterOutbounds = new HashSet<>(outboundByClusterName_.keySet());
    for (final ClusterInformation ci : allCis) {
        final String clusterName = ci.clusterId.clusterName;
        final RoutingStrategy.Router ob = outboundByClusterName_.get(clusterName);
        knownClusterOutbounds.remove(clusterName);
        if (ob != null)
            newOutboundByClusterName.put(clusterName, ob);
        else {
            final RoutingStrategy.Factory obfactory = manager.getAssociatedInstance(ci.routingStrategyTypeId);
            final RoutingStrategy.Router nob = obfactory.getStrategy(ci.clusterId);
            newOutboundByClusterName.put(clusterName, nob);
        }
        // add all of the message types handled.
        ci.messageTypesHandled.forEach(mt -> {
            Set<String> entry = cnByType.get(mt);
            if (entry == null) {
                entry = new HashSet<>();
                cnByType.put(mt, entry);
            }
            entry.add(clusterName);
        });
    }
    return new ApplicationState(newOutboundByClusterName, cnByType, newCurrent, tmanager, thisNode);
}
Also used : NodeInformation(net.dempsy.NodeInformation) Set(java.util.Set) HashSet(java.util.HashSet) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) HashMap(java.util.HashMap) ClusterInformation(net.dempsy.ClusterInformation) Sender(net.dempsy.transport.Sender) RoutingStrategy(net.dempsy.router.RoutingStrategy) NodeAddress(net.dempsy.transport.NodeAddress) HashSet(java.util.HashSet)

Example 3 with Sender

use of net.dempsy.transport.Sender in project Dempsy by Dempsy.

the class ApplicationState method apply.

public ApplicationState apply(final ApplicationState.Update update, final TransportManager tmanager, final NodeStatsCollector statsCollector, final RoutingStrategyManager manager, final String thisNodeId) {
    // apply toDelete first.
    final Set<NodeAddress> toDelete = update.toDelete;
    final boolean infoEnabled = LOGGER_SESSION.isInfoEnabled();
    if (toDelete.size() > 0) {
        // just clear all senders.
        if (infoEnabled)
            LOGGER_SESSION.info("[{}] Applying update to topology resulting in removing several destinations:", thisNodeId);
        for (final NodeAddress a : toDelete) {
            final Sender s = senders.remove(a);
            if (infoEnabled)
                LOGGER_SESSION.info("[{}]      removing sender ({}) to {}", thisNodeId, s, a);
            if (s != null)
                s.stop();
        }
    }
    final Map<NodeAddress, NodeInformation> newCurrent = new HashMap<>();
    // the one's to carry over.
    final Set<NodeInformation> leaveAlone = update.leaveAlone;
    if (leaveAlone.size() > 0)
        if (infoEnabled)
            LOGGER_SESSION.info("[{}] Applying update to topology resulting in leaving several destinations:", thisNodeId);
    for (final NodeInformation cur : leaveAlone) {
        if (infoEnabled)
            LOGGER_SESSION.info("[{}]      leaving alone : {}", thisNodeId, Optional.ofNullable(cur).map(ni -> ni.nodeAddress).orElse(null));
        newCurrent.put(cur.nodeAddress, cur);
    }
    // add new senders
    final Set<NodeInformation> toAdd = update.toAdd;
    if (toAdd.size() > 0)
        if (infoEnabled)
            LOGGER_SESSION.info("[{}] Applying update to topology resulting in adding several destinations:", thisNodeId);
    for (final NodeInformation cur : toAdd) {
        if (infoEnabled)
            LOGGER_SESSION.info("[{}]      adding : {}", thisNodeId, Optional.ofNullable(cur).map(ni -> ni.nodeAddress).orElse(null));
        newCurrent.put(cur.nodeAddress, cur);
    }
    // now flush out the remaining caches.
    // collapse all clusterInfos
    final Set<ClusterInformation> allCis = new HashSet<>();
    newCurrent.values().forEach(ni -> allCis.addAll(ni.clusterInfoByClusterId.values()));
    final Map<String, RoutingStrategy.Router> newOutboundByClusterName = new HashMap<>();
    final Map<String, Set<String>> cnByType = new HashMap<>();
    final Set<String> knownClusterOutbounds = new HashSet<>(outboundByClusterName_.keySet());
    for (final ClusterInformation ci : allCis) {
        final String clusterName = ci.clusterId.clusterName;
        final RoutingStrategy.Router ob = outboundByClusterName_.get(clusterName);
        knownClusterOutbounds.remove(clusterName);
        if (ob != null)
            newOutboundByClusterName.put(clusterName, ob);
        else {
            final RoutingStrategy.Factory obfactory = manager.getAssociatedInstance(ci.routingStrategyTypeId);
            final RoutingStrategy.Router nob = obfactory.getStrategy(ci.clusterId);
            newOutboundByClusterName.put(clusterName, nob);
        }
        // add all of the message types handled.
        ci.messageTypesHandled.forEach(mt -> {
            Set<String> entry = cnByType.get(mt);
            if (entry == null) {
                entry = new HashSet<>();
                cnByType.put(mt, entry);
            }
            entry.add(clusterName);
        });
    }
    return new ApplicationState(newOutboundByClusterName, cnByType, newCurrent, tmanager, thisNode, senders);
}
Also used : Sender(net.dempsy.transport.Sender) TransportManager(net.dempsy.transport.TransportManager) ClusterInformation(net.dempsy.ClusterInformation) ContainerAddress(net.dempsy.router.RoutingStrategy.ContainerAddress) KeyedMessageWithType(net.dempsy.messages.KeyedMessageWithType) NodeAddress(net.dempsy.transport.NodeAddress) Collection(java.util.Collection) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) SenderFactory(net.dempsy.transport.SenderFactory) Set(java.util.Set) HashMap(java.util.HashMap) LOGGER(net.dempsy.intern.OutgoingDispatcher.LOGGER) ArrayList(java.util.ArrayList) RoutingStrategyManager(net.dempsy.router.RoutingStrategyManager) HashSet(java.util.HashSet) NodeStatsCollector(net.dempsy.monitoring.NodeStatsCollector) List(java.util.List) RoutingStrategy(net.dempsy.router.RoutingStrategy) Map(java.util.Map) Optional(java.util.Optional) LOGGER_SESSION(net.dempsy.intern.OutgoingDispatcher.LOGGER_SESSION) NodeInformation(net.dempsy.NodeInformation) NodeInformation(net.dempsy.NodeInformation) Set(java.util.Set) HashSet(java.util.HashSet) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) HashMap(java.util.HashMap) ClusterInformation(net.dempsy.ClusterInformation) Sender(net.dempsy.transport.Sender) RoutingStrategy(net.dempsy.router.RoutingStrategy) NodeAddress(net.dempsy.transport.NodeAddress) HashSet(java.util.HashSet)

Example 4 with Sender

use of net.dempsy.transport.Sender in project Dempsy by Dempsy.

the class BlockingQueueTest method testBlockingQueueOverflow.

/**
 * Test overflow for a blocking Transport around a queue with depth one. While the transport will not call the, and does not even have a , overflow handler,
 * every message will call the overflow handler on
 * the receiver since the queue is always full.
 *
 * @throws Throwable
 */
@Test
public void testBlockingQueueOverflow() throws Throwable {
    final AtomicReference<String> message = new AtomicReference<String>(null);
    final ArrayBlockingQueue<Object> input = new ArrayBlockingQueue<>(1);
    try (@SuppressWarnings("resource") SystemPropertyManager // test only works when the blocking queue blocks
    props = new SystemPropertyManager().set(BlockingQueueSenderFactory.class.getPackageName() + "." + BlockingQueueSenderFactory.BLOCKING_KEY, "true");
        final TestInfrastructure infra = new TestInfrastructure(new DefaultThreadingModel("BQTest-testBlockingQueueOverflow-"));
        final Receiver r = new BlockingQueueReceiver(input);
        final TransportManager tranMan = chain(new TransportManager(), c -> c.start(infra));
        final SenderFactory sf = tranMan.getAssociatedInstance(transportTypeId)) {
        final Sender sender = sf.getSender(r.getAddress(infra));
        final AtomicBoolean finallySent = new AtomicBoolean(false);
        final AtomicLong receiveCount = new AtomicLong();
        // fill up queue
        sender.send("Hello");
        final Thread t = new Thread(() -> {
            try {
                sender.send("Hello again");
            } catch (final MessageTransportException | InterruptedException e) {
                throw new RuntimeException(e);
            }
            finallySent.set(true);
        });
        t.start();
        Thread.sleep(100);
        // the thread should be hung blocked on the send
        assertFalse(finallySent.get());
        // Start the receiver to read
        r.start((final String msg) -> {
            message.set(new String(msg));
            receiveCount.incrementAndGet();
            return true;
        }, infra);
        // 2 messages should have been read and the 2nd should be "Hello again"
        assertTrue(poll(o -> "Hello again".equals(message.get())));
        // The thread should shut down eventually
        assertTrue(poll(o -> !t.isAlive()));
    }
}
Also used : Sender(net.dempsy.transport.Sender) TransportManager(net.dempsy.transport.TransportManager) DefaultThreadingModel(net.dempsy.threading.DefaultThreadingModel) SenderFactory(net.dempsy.transport.SenderFactory) SystemPropertyManager(net.dempsy.util.SystemPropertyManager) Assert.assertTrue(org.junit.Assert.assertTrue) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) Test(org.junit.Test) AtomicReference(java.util.concurrent.atomic.AtomicReference) ArrayBlockingQueue(java.util.concurrent.ArrayBlockingQueue) AtomicLong(java.util.concurrent.atomic.AtomicLong) ConditionPoll.poll(net.dempsy.utils.test.ConditionPoll.poll) Assert.assertFalse(org.junit.Assert.assertFalse) Functional.chain(net.dempsy.util.Functional.chain) TestInfrastructure(net.dempsy.util.TestInfrastructure) MessageTransportException(net.dempsy.transport.MessageTransportException) Receiver(net.dempsy.transport.Receiver) TestInfrastructure(net.dempsy.util.TestInfrastructure) Receiver(net.dempsy.transport.Receiver) AtomicReference(java.util.concurrent.atomic.AtomicReference) DefaultThreadingModel(net.dempsy.threading.DefaultThreadingModel) Sender(net.dempsy.transport.Sender) SystemPropertyManager(net.dempsy.util.SystemPropertyManager) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) AtomicLong(java.util.concurrent.atomic.AtomicLong) ArrayBlockingQueue(java.util.concurrent.ArrayBlockingQueue) MessageTransportException(net.dempsy.transport.MessageTransportException) SenderFactory(net.dempsy.transport.SenderFactory) TransportManager(net.dempsy.transport.TransportManager) Test(org.junit.Test)

Example 5 with Sender

use of net.dempsy.transport.Sender in project Dempsy by Dempsy.

the class TcpTransportTest method testConnectionRecovery.

@Test
public void testConnectionRecovery() throws Exception {
    try (final ServiceTracker tr = new ServiceTracker()) {
        final AbstractTcpReceiver<?, ?> r = tr.track(receiver.get()).numHandlers(2).useLocalHost(true);
        // can't test connection recovery here.
        if (!(r instanceof DisruptableRecevier))
            return;
        final ThreadingModel tm = tr.track(new DefaultThreadingModel(TcpTransportTest.class.getSimpleName() + ".testConnectionRecovery"));
        final Infrastructure infra = tr.track(new TestInfrastructure(tm));
        final TcpAddress addr = r.getAddress(infra);
        LOGGER.debug(addr.toString());
        final AtomicReference<RoutedMessage> rm = new AtomicReference<>(null);
        r.start((Listener<RoutedMessage>) msg -> {
            rm.set(msg);
            return true;
        }, infra);
        try (final SenderFactory sf = senderFactory.get()) {
            sf.start(new TestInfrastructure(tm) {

                @Override
                public String getNodeId() {
                    return "test";
                }
            });
            final Sender sender = sf.getSender(addr);
            sender.send(new RoutedMessage(new int[] { 0 }, "Hello", "Hello"));
            assertTrue(poll(o -> rm.get() != null));
            assertEquals("Hello", rm.get().message);
            assertTrue(((DisruptableRecevier) r).disrupt(addr));
            final AtomicBoolean stop = new AtomicBoolean(false);
            final RoutedMessage resetMessage = new RoutedMessage(new int[] { 0 }, "RESET", "RESET");
            final Thread senderThread = new Thread(() -> {
                try {
                    while (!stop.get()) {
                        sender.send(resetMessage);
                        dontInterrupt(() -> Thread.sleep(100));
                    }
                } catch (final InterruptedException ie) {
                    if (!stop.get())
                        LOGGER.error("Interrupted send");
                }
            }, "testConnectionRecovery-sender");
            senderThread.start();
            try {
                assertTrue(poll(o -> "RESET".equals(rm.get().message)));
            } finally {
                stop.set(true);
                if (!poll(senderThread, t -> {
                    dontInterrupt(() -> t.join(10000));
                    return !t.isAlive();
                }))
                    LOGGER.error("FAILED TO SHUT DOWN TEST SENDING THREAD. THREAD LEAK!");
            }
        }
    }
}
Also used : IntStream(java.util.stream.IntStream) NioReceiver(net.dempsy.transport.tcp.nio.NioReceiver) Arrays(java.util.Arrays) DefaultThreadingModel(net.dempsy.threading.DefaultThreadingModel) NioUtils.dontInterrupt(net.dempsy.transport.tcp.nio.internal.NioUtils.dontInterrupt) Listener(net.dempsy.transport.Listener) RunWith(org.junit.runner.RunWith) Parameters(org.junit.runners.Parameterized.Parameters) LoggerFactory(org.slf4j.LoggerFactory) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) HashMap(java.util.HashMap) AtomicReference(java.util.concurrent.atomic.AtomicReference) Supplier(java.util.function.Supplier) JsonSerializer(net.dempsy.serialization.jackson.JsonSerializer) KryoSerializer(net.dempsy.serialization.kryo.KryoSerializer) Serializer(net.dempsy.serialization.Serializer) Map(java.util.Map) ThreadingModel(net.dempsy.threading.ThreadingModel) TestInfrastructure(net.dempsy.util.TestInfrastructure) ServiceTracker(net.dempsy.ServiceTracker) DisruptableRecevier(net.dempsy.transport.DisruptableRecevier) Receiver(net.dempsy.transport.Receiver) Parameterized(org.junit.runners.Parameterized) NioSenderFactory(net.dempsy.transport.tcp.nio.NioSenderFactory) Sender(net.dempsy.transport.Sender) Logger(org.slf4j.Logger) Collection(java.util.Collection) Functional.uncheck(net.dempsy.util.Functional.uncheck) NetworkInterface(java.net.NetworkInterface) SenderFactory(net.dempsy.transport.SenderFactory) Assert.assertTrue(org.junit.Assert.assertTrue) Test(org.junit.Test) Inet4Address(java.net.Inet4Address) Collectors(java.util.stream.Collectors) CountDownLatch(java.util.concurrent.CountDownLatch) AtomicLong(java.util.concurrent.atomic.AtomicLong) TestWordCount(net.dempsy.TestWordCount) List(java.util.List) ConditionPoll.poll(net.dempsy.utils.test.ConditionPoll.poll) Infrastructure(net.dempsy.Infrastructure) Functional.chain(net.dempsy.util.Functional.chain) Collections(java.util.Collections) Assert.assertEquals(org.junit.Assert.assertEquals) RoutedMessage(net.dempsy.transport.RoutedMessage) TestInfrastructure(net.dempsy.util.TestInfrastructure) ServiceTracker(net.dempsy.ServiceTracker) RoutedMessage(net.dempsy.transport.RoutedMessage) DisruptableRecevier(net.dempsy.transport.DisruptableRecevier) AtomicReference(java.util.concurrent.atomic.AtomicReference) DefaultThreadingModel(net.dempsy.threading.DefaultThreadingModel) Sender(net.dempsy.transport.Sender) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) DefaultThreadingModel(net.dempsy.threading.DefaultThreadingModel) ThreadingModel(net.dempsy.threading.ThreadingModel) TestInfrastructure(net.dempsy.util.TestInfrastructure) Infrastructure(net.dempsy.Infrastructure) NioSenderFactory(net.dempsy.transport.tcp.nio.NioSenderFactory) SenderFactory(net.dempsy.transport.SenderFactory) Test(org.junit.Test)

Aggregations

Sender (net.dempsy.transport.Sender)10 HashMap (java.util.HashMap)8 Map (java.util.Map)7 SenderFactory (net.dempsy.transport.SenderFactory)7 AtomicBoolean (java.util.concurrent.atomic.AtomicBoolean)6 AtomicLong (java.util.concurrent.atomic.AtomicLong)6 AtomicReference (java.util.concurrent.atomic.AtomicReference)6 DefaultThreadingModel (net.dempsy.threading.DefaultThreadingModel)6 Receiver (net.dempsy.transport.Receiver)6 RoutedMessage (net.dempsy.transport.RoutedMessage)6 Functional.chain (net.dempsy.util.Functional.chain)6 TestInfrastructure (net.dempsy.util.TestInfrastructure)6 ConditionPoll.poll (net.dempsy.utils.test.ConditionPoll.poll)6 Assert.assertTrue (org.junit.Assert.assertTrue)6 Test (org.junit.Test)6 Collection (java.util.Collection)5 List (java.util.List)5 Inet4Address (java.net.Inet4Address)4 NetworkInterface (java.net.NetworkInterface)4 Arrays (java.util.Arrays)4