use of net.dempsy.transport.RoutedMessage 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.transport.RoutedMessage 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!");
}
}
}
}
use of net.dempsy.transport.RoutedMessage in project Dempsy by Dempsy.
the class TcpTransportTest method testMessage.
@Test
public void testMessage() throws Exception {
try (ServiceTracker tr = new ServiceTracker()) {
final AbstractTcpReceiver<?, ?> r = tr.track(receiver.get()).numHandlers(2).useLocalHost(true);
final ThreadingModel tm = tr.track(new DefaultThreadingModel(TcpTransportTest.class.getSimpleName() + ".testMessage"));
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);
}
}
}
use of net.dempsy.transport.RoutedMessage in project Dempsy by Dempsy.
the class OutgoingDispatcher method dispatch.
@Override
public void dispatch(final KeyedMessageWithType messageParam, final MessageResourceManager disposer) throws InterruptedException {
final boolean traceEnabled = LOGGER.isTraceEnabled();
if (messageParam == null)
throw new NullPointerException("Attempt to dispatch a null message.");
final Object messageKey = messageParam.key;
if (messageKey == null)
throw new NullPointerException("Message " + SafeString.objectDescription(messageParam) + " has a null key.");
boolean messageSentSomewhere = false;
try (ResourceManagerClosable x = new ResourceManagerClosable(disposer, messageParam)) {
final KeyedMessageWithType message = x.toUse;
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.", thisNodeId);
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) {
if (traceEnabled)
LOGGER.trace("[{}] No cluster that handles messages of type {}", thisNodeId, 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) {
if (LOGGER.isDebugEnabled())
LOGGER.debug("[{}] No way to send the message {} to specific cluster for the time being", thisNodeId, 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);
}
}
}
}
if (containerByNodeAddress.size() == 0) {
if (traceEnabled)
LOGGER.trace("[{}] There appears to be no valid destination addresses for the message {}", thisNodeId, SafeString.objectDescription(message.message));
}
for (final Map.Entry<NodeAddress, ContainerAddress> e : containerByNodeAddress.entrySet()) {
final NodeAddress curNode = e.getKey();
final ContainerAddress curAddr = e.getValue();
// If we're local then just send this message directly back to our own node.
if (curNode.equals(thisNode)) {
if (traceEnabled)
LOGGER.trace("Sending local {}", message);
// if the message is a resource then the disposer will be used to dispose of the message
// but it needs an additional replicate. See propogateMessageToNode javadoc.
nodeReciever.propogateMessageToNode(new RoutedMessage(curAddr.clusters, messageKey, disposer == null ? message.message : disposer.replicate(message.message)), // this shouldn't count since Router is an OUTGOING class
false, disposer);
messageSentSomewhere = true;
} else {
if (traceEnabled)
LOGGER.trace("Sending {} to {}", message, curNode);
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(), thisNodeId);
} else {
sender.send(new RoutedMessage(curAddr.clusters, messageKey, sender.considerMessageOwnsershipTransfered() ? (disposer == null ? message.message : disposer.replicate(message.message)) : message.message));
messageSentSomewhere = true;
}
}
}
} finally {
if (!messageSentSomewhere) {
if (traceEnabled)
LOGGER.trace("Message not sent.");
statsCollector.messageNotSent();
}
}
}
use of net.dempsy.transport.RoutedMessage in project Dempsy by Dempsy.
the class TcpTransportTest method runMultiMessage.
private void runMultiMessage(final String testName, final int numThreads, final int numMessagePerThread, final String message, final Serializer serializer) throws Exception {
try (final ServiceTracker tr = new ServiceTracker()) {
final AbstractTcpReceiver<?, ?> r = tr.track(receiver.get()).numHandlers(2).useLocalHost(true).maxMessageSize(1024 * 1024 * 1024);
final ThreadingModel tm = tr.track(new DefaultThreadingModel(TcpTransportTest.class.getSimpleName() + "." + testName));
final Infrastructure infra = tr.track(new TestInfrastructure(tm));
final TcpAddress addr = r.getAddress(infra);
LOGGER.debug(addr.toString());
final AtomicLong msgCount = new AtomicLong();
r.start((Listener<RoutedMessage>) msg -> {
msgCount.incrementAndGet();
return true;
}, infra);
final AtomicBoolean letMeGo = new AtomicBoolean(false);
final CountDownLatch waitToExit = new CountDownLatch(1);
final List<Thread> threads = IntStream.range(0, numThreads).mapToObj(threadNum -> new Thread(() -> {
try (final SenderFactory sf = senderFactory.get()) {
sf.start(new TestInfrastructure(null, null) {
@Override
public Map<String, String> getConfiguration() {
final Map<String, String> ret = new HashMap<>();
ret.put(sf.getClass().getPackage().getName() + "." + NioSenderFactory.CONFIG_KEY_SENDER_THREADS, NUM_SENDER_THREADS);
return ret;
}
});
final Sender sender = sf.getSender(addr);
while (!letMeGo.get()) Thread.yield();
try {
for (int i = 0; i < numMessagePerThread; i++) sender.send(new RoutedMessage(new int[] { 0 }, "Hello", message));
} catch (final InterruptedException ie) {
LOGGER.error("Interrupted in send.");
}
try {
waitToExit.await();
} catch (final InterruptedException ie) {
}
}
}, "testMultiMessage-Sender-" + threadNum)).map(th -> chain(th, t -> t.start())).collect(Collectors.toList());
Thread.sleep(10);
// here's we go.
letMeGo.set(true);
// the total number of messages sent should be this count.
assertTrue(poll(Long.valueOf((long) numThreads * (long) numMessagePerThread), v -> v.longValue() == msgCount.get()));
// let the threads exit
waitToExit.countDown();
// all threads should eventually exit.
assertTrue(poll(threads, o -> o.stream().filter(t -> t.isAlive()).count() == 0));
}
}
Aggregations