package com.liveramp.hank.loadtest; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; import java.util.Random; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import org.apache.log4j.Level; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.liveramp.hank.client.HankSmartClient; import com.liveramp.hank.client.HankSmartClientOptions; import com.liveramp.hank.config.ClientConfigurator; import com.liveramp.hank.config.yaml.YamlClientConfigurator; import com.liveramp.hank.generated.HankResponse; import com.liveramp.hank.util.CommandLineChecker; public class RandomSaturator { private static final Logger LOG = LoggerFactory.getLogger(RandomSaturator.class); public static class LoadThread extends Thread { private final HankSmartClient client; private final String domainName; private final int numReqs; private final int keyLength; public int hits; private List<Long> times = new ArrayList<Long>(); private final ReadWriteLock lock; private boolean ready = false; private long runStart; private long runEnd; public LoadThread(HankSmartClient client, String domainName, int threadNum, int numReqs, int keyLength, ReadWriteLock lock) throws Exception { super("LoadThread #" + threadNum); this.domainName = domainName; this.numReqs = numReqs; this.keyLength = keyLength; this.lock = lock; this.client = client; } @Override public void run() { ByteBuffer[] keys = new ByteBuffer[numReqs]; Random r = new Random(); for (int i = 0; i < numReqs; i++) { final byte[] bs = new byte[keyLength]; keys[i] = ByteBuffer.wrap(bs); r.nextBytes(bs); } ready = true; lock.readLock().lock(); runStart = System.currentTimeMillis(); for (int i = 0; i < numReqs; i++) { long start = System.currentTimeMillis(); final HankResponse resp = client.get(domainName, keys[i]); if (resp.is_set_xception()) { LOG.error(resp.toString()); } long end = System.currentTimeMillis(); times.add(end - start); if (resp.isSet(HankResponse._Fields.VALUE)) { hits++; } } runEnd = System.currentTimeMillis(); } } public static void main(String[] args) throws Exception { String[] expectedArguments = {"client config file path", "ring group name", "domain name", "num threads", "num requests", "key length", "num connections per host", "query max num tries", "try lock connection timeout ms", "establish connection timeout ms", "query timeout ms", "bulk query timeout ms"}; CommandLineChecker.check(args, expectedArguments, RandomSaturator.class); org.apache.log4j.Logger.getLogger("org.apache.zookeeper").setLevel(Level.ERROR); // parse opts ClientConfigurator configurator = new YamlClientConfigurator(args[0]); String ringGroupName = args[1]; String domainName = args[2]; int numThreads = Integer.parseInt(args[3]); int numReqs = Integer.parseInt(args[4]); int keyLength = Integer.parseInt(args[5]); int numConnectionsPerHost = Integer.parseInt(args[6]); int queryMaxNumTries = Integer.parseInt(args[7]); int tryLockConnectionTimeoutMs = Integer.parseInt(args[8]); int establishConnectionTimeoutMs = Integer.parseInt(args[9]); int queryTimeoutMs = Integer.parseInt(args[10]); int bulkQueryTimeoutMs = Integer.parseInt(args[11]); // set up the delay lock ReadWriteLock lock = new ReentrantReadWriteLock(); lock.writeLock().lock(); final HankSmartClient client = new HankSmartClient(configurator.createCoordinator(), ringGroupName, new HankSmartClientOptions() .setNumConnectionsPerHost(numConnectionsPerHost) .setQueryMaxNumTries(queryMaxNumTries) .setTryLockConnectionTimeoutMs(tryLockConnectionTimeoutMs) .setEstablishConnectionTimeoutMs(establishConnectionTimeoutMs) .setQueryTimeoutMs(queryTimeoutMs) .setBulkQueryTimeoutMs(bulkQueryTimeoutMs)); // instantiate all the threads List<LoadThread> threads = new ArrayList<LoadThread>(); for (int i = 0; i < numThreads; i++) { final LoadThread lt = new LoadThread(client, domainName, i, numReqs, keyLength, lock); threads.add(lt); lt.start(); } // wait for the threads to be ready to run boolean exit = false; while (!exit) { exit = true; for (LoadThread t : threads) { if (!t.ready) { exit = false; } } Thread.sleep(1000); } // release the delay lock lock.writeLock().unlock(); // let all the threads run to completion for (LoadThread t : threads) { t.join(); } // aggregate the results double totalThroughput = 0; for (LoadThread t : threads) { System.err.println("Thread " + t + " had " + t.hits + " hits"); totalThroughput += t.times.size() / ((t.runEnd - t.runStart) / 1000.0); } System.err.println("Total throughput: " + totalThroughput + " req/s"); } }