@Test public void testTopicStats() throws InterruptedException { String topicName = "testTopicStats" + generateRandomString(5); HazelcastInstance instance = createHazelcastInstance(); ITopic<String> topic = instance.getTopic(topicName); final CountDownLatch latch1 = new CountDownLatch(1000); topic.addMessageListener( new MessageListener<String>() { public void onMessage(Message msg) { latch1.countDown(); } }); final CountDownLatch latch2 = new CountDownLatch(1000); topic.addMessageListener( new MessageListener<String>() { public void onMessage(Message msg) { latch2.countDown(); } }); for (int i = 0; i < 1000; i++) { topic.publish("sancar"); } assertTrue(latch1.await(1, TimeUnit.MINUTES)); assertTrue(latch2.await(1, TimeUnit.MINUTES)); LocalTopicStatsImpl stats = (LocalTopicStatsImpl) topic.getLocalTopicStats(); assertEquals(1000, stats.getPublishOperationCount()); assertEquals(2000, stats.getReceiveOperationCount()); }
@Test public void addTwoMessageListener() throws InterruptedException { String topicName = "addTwoMessageListener" + generateRandomString(5); HazelcastInstance instance = createHazelcastInstance(); ITopic<String> topic = instance.getTopic(topicName); final CountDownLatch latch = new CountDownLatch(2); final String message = "Hazelcast Rocks!"; topic.addMessageListener( new MessageListener<String>() { public void onMessage(Message<String> msg) { if (msg.getMessageObject().equals(message)) { latch.countDown(); } } }); topic.addMessageListener( new MessageListener<String>() { public void onMessage(Message<String> msg) { if (msg.getMessageObject().equals(message)) { latch.countDown(); } } }); topic.publish(message); assertTrue(latch.await(10000, TimeUnit.MILLISECONDS)); }
@Test public void testDestroyTopicRemovesStatistics() { String randomTopicName = randomString(); HazelcastInstance instance = createHazelcastInstance(); final ITopic<String> topic = instance.getTopic(randomTopicName); topic.publish("foobar"); // we need to give the message the chance to be processed, else the topic statistics are // recreated // so in theory the destroy for the topic is broken sleepSeconds(1); topic.destroy(); final TopicService topicService = getNode(instance).nodeEngine.getService(TopicService.SERVICE_NAME); assertTrueEventually( new AssertTask() { @Override public void run() { boolean containsStats = topicService.getStatsMap().containsKey(topic.getName()); assertFalse(containsStats); } }); }
@Test public void testName() { String randomTopicName = randomString(); HazelcastInstance hClient = createHazelcastInstance(); ITopic<?> topic = hClient.getTopic(randomTopicName); assertEquals(randomTopicName, topic.getName()); }
@Test public void testTopicPublishingMember() { final int nodeCount = 3; final String randomName = "testTopicPublishingMember" + generateRandomString(5); TestHazelcastInstanceFactory factory = createHazelcastInstanceFactory(nodeCount); HazelcastInstance[] instances = factory.newInstances(); final CountDownLatch mainLatch = new CountDownLatch(nodeCount); final AtomicInteger count1 = new AtomicInteger(0); final AtomicInteger count2 = new AtomicInteger(0); final AtomicInteger count3 = new AtomicInteger(0); for (int i = 0; i < nodeCount; i++) { final HazelcastInstance instance = instances[i]; new Thread( new Runnable() { public void run() { ITopic<Long> topic = instance.getTopic(randomName); topic.addMessageListener( new MessageListener<Long>() { public void onMessage(Message<Long> message) { Member publishingMember = message.getPublishingMember(); if (publishingMember.equals(instance.getCluster().getLocalMember())) count1.incrementAndGet(); if (publishingMember.equals(message.getMessageObject())) count2.incrementAndGet(); if (publishingMember.localMember()) count3.incrementAndGet(); } }); mainLatch.countDown(); } }) .start(); } try { mainLatch.await(1, TimeUnit.MINUTES); } catch (InterruptedException e) { fail(); } for (int i = 0; i < nodeCount; i++) { HazelcastInstance instance = instances[i]; instance.getTopic(randomName).publish(instance.getCluster().getLocalMember()); } assertTrueEventually( new AssertTask() { @Override public void run() { assertEquals(nodeCount, count1.get()); assertEquals(nodeCount * nodeCount, count2.get()); assertEquals(nodeCount, count3.get()); } }); }
/** Testing if topic can properly listen messages and if topic has any issue after a shutdown. */ @Test public void testTopicCluster() throws InterruptedException { String topicName = "TestMessages" + generateRandomString(5); Config cfg = new Config(); TestHazelcastInstanceFactory factory = createHazelcastInstanceFactory(2); HazelcastInstance[] instances = factory.newInstances(cfg); HazelcastInstance instance1 = instances[0]; HazelcastInstance instance2 = instances[1]; ITopic<String> topic1 = instance1.getTopic(topicName); final CountDownLatch latch1 = new CountDownLatch(1); final String message = "Test" + randomString(); topic1.addMessageListener( new MessageListener<String>() { public void onMessage(Message msg) { assertEquals(message, msg.getMessageObject()); latch1.countDown(); } }); ITopic<String> topic2 = instance2.getTopic(topicName); final CountDownLatch latch2 = new CountDownLatch(2); topic2.addMessageListener( new MessageListener<String>() { public void onMessage(Message msg) { assertEquals(message, msg.getMessageObject()); latch2.countDown(); } }); topic1.publish(message); assertTrue(latch1.await(5, TimeUnit.SECONDS)); instance1.shutdown(); topic2.publish(message); assertTrue(latch2.await(5, TimeUnit.SECONDS)); }
@Test public void addTwoListenerAndRemoveOne() throws InterruptedException { String topicName = "addTwoListenerAndRemoveOne" + generateRandomString(5); HazelcastInstance instance = createHazelcastInstance(); ITopic<String> topic = instance.getTopic(topicName); final CountDownLatch latch = new CountDownLatch(3); final CountDownLatch cp = new CountDownLatch(2); final AtomicInteger atomicInteger = new AtomicInteger(); final String message = "Hazelcast Rocks!"; MessageListener<String> messageListener1 = new MessageListener<String>() { public void onMessage(Message<String> msg) { atomicInteger.incrementAndGet(); latch.countDown(); cp.countDown(); } }; MessageListener<String> messageListener2 = new MessageListener<String>() { public void onMessage(Message<String> msg) { atomicInteger.incrementAndGet(); latch.countDown(); cp.countDown(); } }; String messageListenerId = topic.addMessageListener(messageListener1); topic.addMessageListener(messageListener2); topic.publish(message); assertOpenEventually(cp); topic.removeMessageListener(messageListenerId); topic.publish(message); assertOpenEventually(latch); assertEquals(3, atomicInteger.get()); }
@Test public void testPerformance() throws InterruptedException { int count = 10000; String randomTopicName = randomString(); HazelcastInstance instance = createHazelcastInstance(); ExecutorService ex = Executors.newFixedThreadPool(10); final ITopic<String> topic = instance.getTopic(randomTopicName); final CountDownLatch latch = new CountDownLatch(count); for (int i = 0; i < count; i++) { ex.submit( new Runnable() { public void run() { topic.publish("my object"); latch.countDown(); } }); } assertTrue(latch.await(20, TimeUnit.SECONDS)); }
@Test public void testConfigListenerRegistration() throws InterruptedException { String topicName = "default"; Config config = new Config(); final CountDownLatch latch = new CountDownLatch(1); config .getTopicConfig(topicName) .addMessageListenerConfig( new ListenerConfig() .setImplementation( new MessageListener() { public void onMessage(Message message) { latch.countDown(); } })); HazelcastInstance instance = createHazelcastInstance(config); instance.getTopic(topicName).publish(1); assertTrue(latch.await(10, TimeUnit.SECONDS)); }
@Test public void removeMessageListener() throws InterruptedException { String topicName = "removeMessageListener" + generateRandomString(5); try { HazelcastInstance instance = createHazelcastInstance(); ITopic<String> topic = instance.getTopic(topicName); final CountDownLatch latch = new CountDownLatch(2); final CountDownLatch cp = new CountDownLatch(1); MessageListener<String> messageListener = new MessageListener<String>() { public void onMessage(Message<String> msg) { latch.countDown(); cp.countDown(); } }; final String message = "message_" + messageListener.hashCode() + "_"; final String id = topic.addMessageListener(messageListener); topic.publish(message + "1"); cp.await(); topic.removeMessageListener(id); topic.publish(message + "2"); assertTrueEventually( new AssertTask() { @Override public void run() { assertEquals(1, latch.getCount()); } }); } finally { shutdownNodeFactory(); } }
public class Node { final HazelcastInstance hazelcast = Hazelcast.newHazelcastInstance(null); final ITopic<StockPriceUpdate> topicFeed = hazelcast.getTopic("feed"); final IQueue<Order> qOrders = hazelcast.getQueue("orders"); final IMap<String, Position> mapPositions = hazelcast.getMap("positions"); // <pmId,instrumentId, Position> final IMap<Integer, Integer> mapNewOrders = hazelcast.getMap("neworders"); // <pmId, instrumentId> final AtomicLong countReceivedStockUpdates = new AtomicLong(); final AtomicLong countOrdersProcessed = new AtomicLong(); final AtomicLong countNewOrderEvents = new AtomicLong(); final AtomicLong countPositionViews = new AtomicLong(); final Logger logger = Logger.getLogger("Node"); final ITopic<String> topicLogs = hazelcast.getTopic("logs"); final ConcurrentMap<Integer, Double> mapStockPrices = new ConcurrentHashMap<Integer, Double>(8000); final String memberString = hazelcast.getCluster().getLocalMember().toString(); final int threads = 100; final ExecutorService esOrderConsumer = Executors.newFixedThreadPool(threads); final ExecutorService esEventProcessor = Executors.newFixedThreadPool(10); final ConcurrentMap<Integer, Portfolio> localPMPositions = new ConcurrentHashMap<Integer, Portfolio>(); final ConcurrentMap<Integer, InstrumentInfo> mapInstrumentInfos = new ConcurrentHashMap<Integer, InstrumentInfo>(); public static void main(String[] args) { System.setProperty("hazelcast.mc.topic.excludes", "pm.*"); new Node().init(); } void init() { for (int i = 0; i < threads; i++) { esOrderConsumer.execute(new PositionQueueSlurper()); } topicFeed.addMessageListener(new StockStreamListener()); mapNewOrders.addLocalEntryListener(new NewOrderListener()); startStreamer(); Executors.newSingleThreadExecutor() .execute( new Runnable() { public void run() { while (true) { try { Thread.sleep(5000); long feeds = countReceivedStockUpdates.getAndSet(0) / 5; long orders = countOrdersProcessed.getAndSet(0) / 5; long events = countNewOrderEvents.getAndSet(0) / 5; long views = countPositionViews.getAndSet(0) / 5; log( "Feeds:" + feeds + ", OrdersProcessed:" + orders + ", newOrderEvents:" + events + ", Views:" + views); } catch (Exception e) { e.printStackTrace(); } } } }); } void startStreamer() { final Timer timer = new Timer(); timer.scheduleAtFixedRate( new TimerTask() { @Override public void run() { for (int i = 0; i < 500; i++) { double price = (int) (Math.random() * 50) + 1; topicFeed.publish( new StockPriceUpdate(LookupDatabase.randomPickInstrument().id, price)); } } }, 0, 1000); } class StockStreamListener implements MessageListener<StockPriceUpdate> { public void onMessage(final Message<StockPriceUpdate> stockPriceUpdate) { esEventProcessor.execute( new Runnable() { public void run() { countReceivedStockUpdates.incrementAndGet(); int instrumentId = stockPriceUpdate.getMessageObject().getInstrumentId(); mapStockPrices.put(instrumentId, stockPriceUpdate.getMessageObject().getPrice()); InstrumentInfo instrumentInfo = createOrGetInstrumentInfo(instrumentId); Collection<Portfolio> relatedPortfolios = instrumentInfo.getPortfolios(); for (Portfolio relatedPortfolio : relatedPortfolios) { firePositionViewChanged(createPositionView(relatedPortfolio, instrumentId)); } } }); } } private void firePositionViewChanged(PositionView positionView) { if (positionView == null) return; countPositionViews.incrementAndGet(); ITopic topicPM = hazelcast.getTopic("pm_" + positionView.pmId); topicPM.publish(positionView); } public PositionView createPositionView(Portfolio portfolio, Integer instrumentId) { Double lastPrice = mapStockPrices.get(instrumentId); if (lastPrice == null) return null; Position position = portfolio.getPosition(instrumentId); return new PositionView( portfolio.pmId, instrumentId, position.quantity, lastPrice, position.calculateProfitLoss(lastPrice)); } private Portfolio createOrGetPortfolio(int pmId) { Portfolio portfolio = localPMPositions.get(pmId); if (portfolio == null) { portfolio = new Portfolio(pmId); Portfolio existing = localPMPositions.putIfAbsent(pmId, portfolio); if (existing != null) { portfolio = existing; } } return portfolio; } private InstrumentInfo createOrGetInstrumentInfo(int instrumentId) { InstrumentInfo instrumentInfo = mapInstrumentInfos.get(instrumentId); if (instrumentInfo == null) { instrumentInfo = new InstrumentInfo(); InstrumentInfo existing = mapInstrumentInfos.putIfAbsent(instrumentId, instrumentInfo); if (existing != null) { instrumentInfo = existing; } } return instrumentInfo; } class NewOrderListener implements EntryListener<Integer, Integer> { public void entryAdded(final EntryEvent<Integer, Integer> entryEvent) { countNewOrderEvents.incrementAndGet(); esEventProcessor.execute( new Runnable() { public void run() { Integer pmId = entryEvent.getKey(); Integer instrumentId = entryEvent.getValue(); // load all positions for this pm // and create the Portfolio } }); } public void entryRemoved(final EntryEvent<Integer, Integer> entryEvent) {} public void entryUpdated(final EntryEvent<Integer, Integer> entryEvent) { countNewOrderEvents.incrementAndGet(); esEventProcessor.execute( new Runnable() { public void run() { try { Integer pmId = entryEvent.getKey(); Integer instrumentId = entryEvent.getValue(); Position position = mapPositions.get(pmId + "," + instrumentId); if (position != null) { Portfolio portfolio = createOrGetPortfolio(pmId); InstrumentInfo instrumentInfo = createOrGetInstrumentInfo(instrumentId); instrumentInfo.addPortfolio(portfolio); portfolio.update(position); PositionView positionView = createPositionView(portfolio, instrumentId); firePositionViewChanged(positionView); } } catch (Throwable e) { e.printStackTrace(); } } }); } public void entryEvicted(final EntryEvent<Integer, Integer> entryEvent) {} } void log(String msg) { if (msg != null) { logger.info(msg); topicLogs.publish(memberString + ": " + msg); } } public class PositionQueueSlurper implements Runnable { public void run() { while (true) { TransactionContext context = hazelcast.newTransactionContext(); context.beginTransaction(); Set<Integer> setAllInvolvedPMs = new HashSet<Integer>(9); try { Order order = qOrders.take(); countOrdersProcessed.incrementAndGet(); List<Integer> lsAccounts = order.lsAccounts; int accountQuantity = order.quantity / lsAccounts.size(); // for (Integer account : lsAccounts) { // String key = account + "," + order.instrumentId; // updatePosition(key, order, account, accountQuantity); // } String key = order.portfolioManagerId + "," + order.instrumentId; updatePosition(key, order, order.portfolioManagerId, order.quantity); context.commitTransaction(); // setAllInvolvedPMs.addAll(lsAccounts); setAllInvolvedPMs.add(order.portfolioManagerId); for (Integer involvedPM : setAllInvolvedPMs) { mapNewOrders.put(involvedPM, order.instrumentId); } } catch (Throwable t) { t.printStackTrace(); context.rollbackTransaction(); } } } public void updatePosition(String key, Order order, int pmId, int quantity) { Deal deal = new Deal(quantity, order.price); Position position = mapPositions.get(key); if (position == null) { position = new Position(order.instrumentId); } else if (position.getDealSize() > 100) { for (int i = 0; i < 10; i++) { position.lsDeals.remove(0); } } position.addDeal(deal); mapPositions.put(key, position); } } }
private void firePositionViewChanged(PositionView positionView) { if (positionView == null) return; countPositionViews.incrementAndGet(); ITopic topicPM = hazelcast.getTopic("pm_" + positionView.pmId); topicPM.publish(positionView); }
public ITopic<Object> getTopic() { // if (topic == null) { topic = hazelcast.getTopic(namespace); // } return topic; }