package com.ctriposs.sdb; import com.ctriposs.sdb.utils.TestUtil; import org.junit.Test; import java.util.Queue; import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicInteger; import static org.junit.Assert.*; /** * Simulate producer & consumer * * Created by z_wu on 2014/5/26. */ public class SDBPerfTestB { private static String testDir = TestUtil.TEST_BASE_DIR + "sdb_perf_testb"; private static SDB db; private static BlockingQueue<byte[]> keysInMemoryQueue = new LinkedBlockingQueue<byte[]>(); private static final AtomicInteger producingItemCount = new AtomicInteger(0); private static final AtomicInteger consumingItemCount = new AtomicInteger(0); // configurable parameters ////////////////////////////////////////////////////////////////// private static int loop = 5; private static int totalItemCount = 1000000; private static int producerNum = 4; private static int consumerNum = 4; private static int messageMaxLength = 16; ////////////////////////////////////////////////////////////////// @Test public void testProducerAndConsumer() throws Exception{ System.out.println("SDB performance test begin ..."); for(int i = 0; i < loop; i++) { db = new SDB(testDir); System.out.println("[doRunProduceThenConsume] round " + (i + 1) + " of " + loop); this.doRunProduceThenConsume(); producingItemCount.set(0); consumingItemCount.set(0); db.close(); db.destory(); } System.out.println("[doRunProduceThenConsume] test ends"); //Mixed type test System.out.println("Mixed type test begin"); for(int i = 0; i < loop; i++) { db = new SDB(testDir); System.out.println("[doRunMixed] round " + (i + 1) + " of " + loop); this.doRunMixed(); producingItemCount.set(0); consumingItemCount.set(0); db.close(); db.destory(); } System.out.println("[doRunMixed] test ends"); System.out.println("Test on SDB finished successfully"); } private static enum Status { ERROR, SUCCESS } private static class Result { Status status; long duration; } 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(); try { latch.countDown(); latch.await(); long start = System.nanoTime(); while(true) { int count = producingItemCount.incrementAndGet(); if(count > totalItemCount) break; byte[] key = TestUtil.randomString(messageMaxLength).getBytes(); keysInMemoryQueue.offer(key); db.put(key, key); } long end = System.nanoTime(); result.status = Status.SUCCESS; result.duration = end - start; } 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(); result.status = Status.SUCCESS; try { latch.countDown(); latch.await(); long start = System.nanoTime(); while(true) { int count = consumingItemCount.getAndIncrement(); if (count >= totalItemCount) break; byte[] keyBytes = keysInMemoryQueue.take(); if(keyBytes != null) { byte[] valueBytes = db.get(keyBytes); // wait a moment for k/v to be put in the DB while(valueBytes == null) { valueBytes = db.get(keyBytes); } if (!new String(keyBytes).equals(new String(valueBytes))) { result.status = Status.ERROR; } } } long end = System.nanoTime(); result.duration = end - start; } catch (Exception e) { e.printStackTrace(); result.status = Status.ERROR; } resultQueue.offer(result); } } public void doRunProduceThenConsume() throws InterruptedException{ CountDownLatch producerLatch = new CountDownLatch(producerNum); CountDownLatch consumerLatch = new CountDownLatch(consumerNum); BlockingQueue<Result> producerResults = new LinkedBlockingQueue<Result>(); BlockingQueue<Result> consumerResults = new LinkedBlockingQueue<Result>(); long totalProducingTime = 0; long totalConsumingTime = 0; long start = System.nanoTime(); // the producer start for(int i = 0; i < producerNum; i++) { Producer p = new Producer(producerLatch, producerResults); p.start(); } for(int i = 0; i < producerNum; i++) { Result result = producerResults.take(); assertEquals(result.status, Status.SUCCESS); totalProducingTime += result.duration; } long end = System.nanoTime(); System.out.println("-----------------------------------------------"); System.out.println("Producing test result:"); System.out.printf("Total test time = %d ns.\n", (end - start)); System.out.printf("Total item count = %d\n", totalItemCount); System.out.printf("Producer thread number = %d\n", producerNum); System.out.printf("Item message length = %d bytes\n", messageMaxLength); System.out.printf("Total producing time = %d ns.\n", totalProducingTime); System.out.printf("Average producint time = %d ns.\n", totalProducingTime / producerNum); System.out.println("-----------------------------------------------"); TestUtil.getSDBStats(db.getStats()); // the consumer start start = System.nanoTime(); for(int i = 0; i < consumerNum; i++) { Consumer c = new Consumer(consumerLatch, consumerResults); c.start(); } for(int i = 0; i < consumerNum; i++) { Result result = consumerResults.take(); assertEquals(result.status, Status.SUCCESS); totalConsumingTime += result.duration; } end = System.nanoTime(); assertEquals(producingItemCount.get(), consumingItemCount.get()); assertTrue(keysInMemoryQueue.isEmpty()); System.out.println("Consuming test result:"); System.out.printf("Total test time = %d ns.\n", (end - start)); System.out.printf("Total item count = %d\n", totalItemCount); System.out.printf("Consumer thread number = %d\n", consumerNum); System.out.printf("Item message length = %d bytes\n", messageMaxLength); System.out.printf("Total consuming time = %d ns.\n", totalConsumingTime); System.out.printf("Average consuming time = %d ns.\n", totalConsumingTime / consumerNum); System.out.println("-----------------------------------------------"); } public void doRunMixed() throws Exception { //prepare CountDownLatch allLatch = new CountDownLatch(producerNum + consumerNum); BlockingQueue<Result> producerResults = new LinkedBlockingQueue<Result>(); BlockingQueue<Result> consumerResults = new LinkedBlockingQueue<Result>(); long totalProducingTime = 0; long totalConsumingTime = 0; long start = System.nanoTime(); //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 and report for(int i = 0; i < producerNum; i++) { Result result = producerResults.take(); assertEquals(result.status, Status.SUCCESS); totalProducingTime += result.duration; } for(int i = 0; i < consumerNum; i++) { Result result = consumerResults.take(); assertEquals(result.status, Status.SUCCESS); totalConsumingTime += result.duration; } long end = System.nanoTime(); assertEquals(producingItemCount.get(), consumingItemCount.get()); System.out.println("-----------------------------------------------"); System.out.printf("Total test time = %d ns.\n", (end - start)); System.out.printf("Total item count = %d\n", totalItemCount); System.out.printf("Producer thread number = %d\n", producerNum); System.out.printf("Consumer thread number = %d\n", consumerNum); System.out.printf("Item message length = %d bytes\n", messageMaxLength); System.out.printf("Total consuming time = %d ns.\n", totalConsumingTime); System.out.printf("Average consuming time = %d ns.\n", totalConsumingTime / consumerNum); System.out.printf("Total producing time = %d ns.\n", totalProducingTime); System.out.printf("Average producing time = %d ns.\n", totalProducingTime / producerNum); System.out.println("-----------------------------------------------"); } }