use of net.dempsy.router.RoutingStrategy.ContainerAddress 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.router.RoutingStrategy.ContainerAddress in project Dempsy by Dempsy.
the class TestGroupRoutingStrategy method testInboundDoubleHappyPathRegister.
@Test
public void testInboundDoubleHappyPathRegister() throws Exception {
final int numShardsToExpect = Integer.parseInt(Utils.DEFAULT_TOTAL_SHARDS);
final String groupName = "testInboundDoubleHappyPathRegister";
try (final RoutingStrategy.Inbound ib1 = new RoutingInboundManager().getAssociatedInstance(ClusterGroupInbound.class.getPackage().getName() + ":" + groupName);
final RoutingStrategy.Inbound ib2 = new RoutingInboundManager().getAssociatedInstance(ClusterGroupInbound.class.getPackage().getName() + ":" + groupName)) {
final ClusterId clusterId = new ClusterId("test", "test");
final NodeAddress node1Addr = new DummyNodeAddress("node1");
final GroupDetails gd1 = new GroupDetails(groupName, node1Addr);
final ContainerAddress node1Ca = new ContainerAddress(node1Addr, 0);
final Utils<GroupDetails> utils = new Utils<>(infra, groupName, gd1);
ib1.setContainerDetails(clusterId, node1Ca, (l, m) -> {
});
ib1.start(infra);
final NodeAddress node2Addr = new DummyNodeAddress("node2");
final ContainerAddress node2Ca = new ContainerAddress(node2Addr, 0);
ib2.setContainerDetails(clusterId, node2Ca, (l, m) -> {
});
try (final ClusterInfoSession session2 = sessFact.createSession()) {
ib2.start(new TestInfrastructure(session2, infra.getScheduler()));
assertTrue(waitForShards(session, utils, numShardsToExpect));
// if this worked right then numShardsToExpect/2 should be owned by each ... eventually.
checkForShardDistribution(session, utils, numShardsToExpect, 2);
// disrupt the session. This should cause a reshuffle but not fail
disruptor.accept(session2);
// everything should settle back
checkForShardDistribution(session, utils, numShardsToExpect, 2);
// now kill the second session.
// this will disconnect the second Inbound and so the first should take over
session2.close();
// see if we now have 1 session and it has all shards
checkForShardDistribution(session, utils, numShardsToExpect, 1);
}
}
}
use of net.dempsy.router.RoutingStrategy.ContainerAddress in project Dempsy by Dempsy.
the class TestGroupRoutingStrategy method testInboundWithOutbound.
@Test
public void testInboundWithOutbound() throws Exception {
final int numShardsToExpect = Integer.parseInt(Utils.DEFAULT_TOTAL_SHARDS);
final String groupName = "testInboundWithOutbound";
final Manager<RoutingStrategy.Inbound> manager = new RoutingInboundManager();
try (final RoutingStrategy.Inbound ib = manager.getAssociatedInstance(ClusterGroupInbound.class.getPackage().getName() + ":" + groupName)) {
final ClusterId cid = setTestName("testInboundWithOutbound");
final NodeAddress na = new DummyNodeAddress("here");
final ContainerAddress oca = new ContainerAddress(na, 0);
final Infrastructure infra = makeInfra(session, sched);
final GroupDetails ogd = new GroupDetails(groupName, na);
final Map<String, ContainerAddress> ocaiByCluster = new HashMap<>();
ocaiByCluster.put(cid.clusterName, oca);
ogd.fillout(ocaiByCluster);
final Utils<GroupDetails> msutils = new Utils<>(infra, groupName, ogd);
ib.setContainerDetails(cid, oca, (l, m) -> {
});
ib.start(infra);
checkForShardDistribution(session, msutils, numShardsToExpect, 1);
try (final ClusterInfoSession ses2 = sessFact.createSession();
final RoutingStrategyManager obman = chain(new RoutingStrategyManager(), o -> o.start(makeInfra(ses2, sched)));
final RoutingStrategy.Factory obf = obman.getAssociatedInstance(ClusterGroupInbound.class.getPackage().getName() + ":" + groupName)) {
obf.start(makeInfra(ses2, sched));
assertTrue(poll(o -> obf.isReady()));
final RoutingStrategy.Router ob = obf.getStrategy(cid);
assertTrue(poll(o -> obf.isReady()));
final KeyedMessageWithType km = new KeyedMessageWithType(new Object(), new Object(), "");
assertTrue(poll(o -> ob.selectDestinationForMessage(km) != null));
final ContainerAddress ca = ob.selectDestinationForMessage(km);
assertNotNull(ca);
assertEquals("here", ((DummyNodeAddress) ca.node).name);
// now disrupt the session
session.close();
// the destination should clear until a new one runs
// NO: destination will not necessarily clear.
// poll(o -> ob.selectDestinationForMessage(km) == null);
final ContainerAddress nca = new ContainerAddress(new DummyNodeAddress("here-again"), 0);
ogd.fillout(ocaiByCluster);
try (ClusterInfoSession ses3 = sessFact.createSession();
RoutingStrategy.Inbound ib2 = new RoutingInboundManager().getAssociatedInstance(ClusterGroupInbound.class.getPackage().getName() + ":" + groupName)) {
ib2.setContainerDetails(cid, nca, (l, m) -> {
});
ib2.start(makeInfra(ses3, sched));
assertTrue(poll(o -> ob.selectDestinationForMessage(km) != null));
}
}
}
}
use of net.dempsy.router.RoutingStrategy.ContainerAddress in project Dempsy by Dempsy.
the class TestLeaderAndSubscriber method testOneLeader.
@Test
public void testOneLeader() throws InterruptedException {
final ClusterId cid = setTestName("testOneLeader");
final Utils<ContainerAddress> utils = new Utils<ContainerAddress>(makeInfra(session, sched), cid.clusterName, new ContainerAddress(new DummyNodeAddress(), new int[] { 0 }));
final AtomicBoolean isRunning = new AtomicBoolean(true);
try {
final Leader<ContainerAddress> l = new Leader<ContainerAddress>(utils, 256, 1, infra, isRunning, ContainerAddress[]::new);
l.process();
assertTrue(poll(o -> l.imIt()));
} finally {
isRunning.set(false);
}
}
use of net.dempsy.router.RoutingStrategy.ContainerAddress in project Dempsy by Dempsy.
the class TestLeaderAndSubscriber method testLeaderWithMutipleSubscribers.
@Test
public void testLeaderWithMutipleSubscribers() throws Exception {
final int NUM_SUBS = 10;
final ClusterId cid = setTestName("testLeaderWithMutipleSubscribers");
final AtomicBoolean isRunning = new AtomicBoolean(true);
final List<Thread> threads = new ArrayList<>();
try {
final List<Subscriber<ContainerAddress>> subs = new ArrayList<>();
final AtomicBoolean go = new AtomicBoolean(false);
for (int i = 0; i < NUM_SUBS; i++) {
final Utils<ContainerAddress> utils = new Utils<>(makeInfra(session, sched), cid.clusterName, new ContainerAddress(new DummyNodeAddress(), new int[] { 0 }));
final Subscriber<ContainerAddress> s;
subs.add(s = new Subscriber<>(utils, infra, isRunning, (l, m) -> {
}, 256));
final Thread t = new Thread(() -> {
// wait for it.
while (!go.get()) {
if (!isRunning.get())
return;
Thread.yield();
}
s.process();
}, "testLeaderWithMutipleSubscribers-" + i);
t.start();
threads.add(t);
}
go.set(true);
final Utils<ContainerAddress> utils = new Utils<>(makeInfra(session, sched), cid.clusterName, subs.get(3).getUtils().thisNodeAddress);
final Leader<ContainerAddress> l = new Leader<>(utils, 256, 1, infra, isRunning, ContainerAddress[]::new);
l.process();
assertTrue(poll(o -> l.imIt()));
// wait until ready
assertTrue(poll(o -> subs.stream().filter(s -> s.isReady()).count() == NUM_SUBS));
final int lowerNum = Math.floorDiv(256, NUM_SUBS);
final int upperNum = (int) Math.ceil((double) 256 / NUM_SUBS);
// do we have balanced subs?
assertTrue(poll(o -> subs.stream().filter(s -> s.numShardsIOwn() >= lowerNum).filter(s -> s.numShardsIOwn() <= upperNum).count() == NUM_SUBS));
isRunning.set(false);
assertTrue(poll(o -> threads.stream().filter(t -> t.isAlive()).count() == 0));
} finally {
isRunning.set(false);
}
}
Aggregations