package com.netflix.suro.queue; import com.netflix.suro.message.Message; import com.netflix.suro.message.MessageSerDe; import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; import java.io.IOException; import java.util.Collections; import java.util.Queue; import java.util.Random; import java.util.Set; import java.util.concurrent.BlockingQueue; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CountDownLatch; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.atomic.AtomicInteger; import static org.junit.Assert.*; @Ignore public class FileQueueLoadTest { @Rule public TemporaryFolder tempDir = new TemporaryFolder(); private static FileBlockingQueue<Message> bigQueue; // configurable parameters ////////////////////////////////////////////////////////////////// private static int loop = 5; private static int totalItemCount = 100000; private static int producerNum = 4; private static int consumerNum = 1; private static int messageLength = 1024; ////////////////////////////////////////////////////////////////// private static enum Status { ERROR, SUCCESS } private static class Result { Status status; } private static final AtomicInteger producingItemCount = new AtomicInteger(0); private static final AtomicInteger consumingItemCount = new AtomicInteger(0); private static final Set<String> itemSet = Collections.newSetFromMap(new ConcurrentHashMap<String,Boolean>()); static final String AB = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; static Random rnd = new Random(); public static String randomString(int len ) { StringBuilder sb = new StringBuilder( len ); for( int i = 0; i < len; i++ ) sb.append( AB.charAt( rnd.nextInt(AB.length()) ) ); return sb.toString(); } private static class Producer extends Thread { private final CountDownLatch latch; private final Queue<Result> resultQueue; public Producer(CountDownLatch latch, Queue<Result> resultQueue) { this.latch = latch; this.resultQueue = resultQueue; } public void run() { Result result = new Result(); String rndString = randomString(messageLength); try { latch.countDown(); latch.await(); while(true) { int count = producingItemCount.incrementAndGet(); if(count > totalItemCount) break; String item = rndString + count; itemSet.add(item); bigQueue.put(new Message("routing", item.getBytes())); } result.status = Status.SUCCESS; } catch (Exception e) { e.printStackTrace(); result.status = Status.ERROR; } resultQueue.offer(result); } } private static class Consumer extends Thread { private final CountDownLatch latch; private final Queue<Result> resultQueue; public Consumer(CountDownLatch latch, Queue<Result> resultQueue) { this.latch = latch; this.resultQueue = resultQueue; } public void run() { Result result = new Result(); try { latch.countDown(); latch.await(); while(true) { int index = consumingItemCount.getAndIncrement(); if (index >= totalItemCount) break; Message item = bigQueue.take(); assertNotNull(item); assertTrue(itemSet.remove(new String(item.getPayload()))); } result.status = Status.SUCCESS; } catch (Exception e) { e.printStackTrace(); result.status = Status.ERROR; } resultQueue.offer(result); } } @Test public void runTest() throws Exception { createQueue(); System.out.println("Load test begin ..."); for(int i = 0; i < loop; i++) { System.out.println("[doRunProduceThenConsume] round " + (i + 1) + " of " + loop); this.doRunProduceThenConsume(); // reset producingItemCount.set(0); consumingItemCount.set(0); } bigQueue.close(); createQueue(); for(int i = 0; i < loop; i++) { System.out.println("[doRunMixed] round " + (i + 1) + " of " + loop); this.doRunMixed(); // reset producingItemCount.set(0); consumingItemCount.set(0); } System.out.println("Load test finished successfully."); } private void createQueue() throws IOException { bigQueue = new FileBlockingQueue<Message>(tempDir.newFolder().getAbsolutePath(), "load_test", 1, new MessageSerDe()); } public void doRunProduceThenConsume() throws Exception { //prepare CountDownLatch platch = new CountDownLatch(producerNum); CountDownLatch clatch = new CountDownLatch(consumerNum); BlockingQueue<Result> producerResults = new LinkedBlockingQueue<Result>(); BlockingQueue<Result> consumerResults = new LinkedBlockingQueue<Result>(); //run testing for(int i = 0; i < producerNum; i++) { Producer p = new Producer(platch, producerResults); p.start(); } for(int i = 0; i < producerNum; i++) { Result result = producerResults.take(); assertEquals(result.status, Status.SUCCESS); } assertTrue(!bigQueue.isEmpty()); assertEquals(bigQueue.size(), totalItemCount); assertEquals(itemSet.size(), totalItemCount); for(int i = 0; i < consumerNum; i++) { Consumer c = new Consumer(clatch, consumerResults); c.start(); } for(int i = 0; i < consumerNum; i++) { Result result = consumerResults.take(); assertEquals(result.status, Status.SUCCESS); } assertTrue(itemSet.isEmpty()); assertTrue(bigQueue.isEmpty()); assertTrue(bigQueue.size() == 0); } public void doRunMixed() throws Exception { //prepare CountDownLatch allLatch = new CountDownLatch(producerNum + consumerNum); BlockingQueue<Result> producerResults = new LinkedBlockingQueue<Result>(); BlockingQueue<Result> consumerResults = new LinkedBlockingQueue<Result>(); //run testing for(int i = 0; i < producerNum; i++) { Producer p = new Producer(allLatch, producerResults); p.start(); } for(int i = 0; i < consumerNum; i++) { Consumer c = new Consumer(allLatch, consumerResults); c.start(); } //verify for(int i = 0; i < producerNum; i++) { Result result = producerResults.take(); assertEquals(result.status, Status.SUCCESS); } for(int i = 0; i < consumerNum; i++) { Result result = consumerResults.take(); assertEquals(result.status, Status.SUCCESS); } assertTrue(itemSet.isEmpty()); assertTrue(bigQueue.isEmpty()); assertTrue(bigQueue.size() == 0); } }