/* * Copyright 2008-2010 LinkedIn, Inc * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package voldemort.performance; import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import joptsimple.OptionParser; import joptsimple.OptionSet; import voldemort.client.ClientConfig; import voldemort.client.SocketStoreClientFactory; import voldemort.client.StoreClient; import voldemort.client.StoreClientFactory; import voldemort.client.TimeoutConfig; import voldemort.utils.CmdUtils; /** * Stress tests the client. Intended to diagnose issues such as connection leaks */ public class ClientConnectionStressTest { private static final String CONNECTION_TIMEOUT = "connection-timeout"; private static final String ROUTING_TIMEOUT = "routing-timeout"; private static final String SOCKET_TIMEOUT = "socket-timeout"; private static final String MAX_CONNECTIONS = "max-connections"; private static final String MAX_CONNECTIONS_TOTAL = "max-connections-total"; private static final String MAX_THREADS = "max-threads"; private static final String SELECTORS = "selectors"; private static final String SOCKET_BUFFER_SIZE = "socket-buffer-size"; private static final String REQS = "reqs"; private static final String CONNECTIONS = "connections"; private final String storeName; private final int connsParallel; private final int connsTotal; private final int reqsPerConn; private final ExecutorService executor; private final StoreClientFactory factory; public ClientConnectionStressTest(ClientConfig config, String storeName, int connsParallel, int connsTotal, int reqsPerConn) { this.storeName = storeName; this.connsParallel = connsParallel; this.connsTotal = connsTotal; this.reqsPerConn = reqsPerConn; this.executor = Executors.newFixedThreadPool(connsParallel); this.factory = new SocketStoreClientFactory(config); } public void execute() throws Exception { for(int i = 0; i < connsTotal; i++) { final CountDownLatch latch = new CountDownLatch(connsParallel); for(int j = 0; j < connsParallel; j++) { System.out.println("Connection " + (i + j)); executor.submit(new Runnable() { public void run() { try { StoreClient<String, String> client = factory.getStoreClient(storeName); for(int k = 0; k < reqsPerConn; k++) client.get(Integer.toString(k)); } finally { latch.countDown(); } } }); } latch.await(); } executor.shutdown(); } @SuppressWarnings("unchecked") public static void main(String[] args) throws Exception { OptionParser parser = new OptionParser(); parser.accepts(CONNECTION_TIMEOUT, "Connection timeout (ms)") .withRequiredArg() .ofType(Integer.class); parser.accepts(ROUTING_TIMEOUT, "Routing timeout (ms)") .withRequiredArg() .ofType(Integer.class); parser.accepts(SOCKET_TIMEOUT, "Socket timeout (ms)") .withRequiredArg() .ofType(Integer.class); parser.accepts(MAX_CONNECTIONS, "Max connections per node") .withRequiredArg() .ofType(Integer.class); parser.accepts(MAX_CONNECTIONS_TOTAL, "Max total connections") .withRequiredArg() .ofType(Integer.class); parser.accepts(MAX_THREADS, "Max threads").withRequiredArg().ofType(Integer.class); parser.accepts(SELECTORS, "Number of NIO selectors") .withRequiredArg() .ofType(Integer.class); parser.accepts(SOCKET_BUFFER_SIZE, "Socket buffer size") .withRequiredArg() .ofType(Integer.class); parser.accepts(REQS, "Requests per session").withRequiredArg().ofType(Integer.class); parser.accepts(CONNECTIONS, "Total connections to make") .withRequiredArg() .ofType(Integer.class); parser.accepts("help"); OptionSet options = parser.parse(args); List<String> rest = (List<String>) options.nonOptionArguments(); if(rest.size() < 2 || options.has("help")) { parser.printHelpOn(System.err); System.err.println("Usage: ClientConnectionStressTest <options> url store-name"); System.exit(0); } String url = rest.get(0); String storeName = rest.get(1); Integer connsTotal = CmdUtils.valueOf(options, CONNECTIONS, 100); Integer reqs = CmdUtils.valueOf(options, REQS, 1000); ClientConfig config = new ClientConfig(); if(options.has(CONNECTION_TIMEOUT)) config.setConnectionTimeout((Integer) options.valueOf(CONNECTION_TIMEOUT), TimeUnit.MILLISECONDS); if(options.has(ROUTING_TIMEOUT)) config.setTimeoutConfig(new TimeoutConfig(TimeUnit.MILLISECONDS.toMillis((Integer) options.valueOf(ROUTING_TIMEOUT)), false)); if(options.has(SOCKET_TIMEOUT)) config.setSocketTimeout((Integer) options.valueOf(SOCKET_TIMEOUT), TimeUnit.MILLISECONDS); if(options.has(MAX_CONNECTIONS)) config.setMaxConnectionsPerNode((Integer) options.valueOf(MAX_CONNECTIONS)); if(options.has(MAX_THREADS)) config.setMaxThreads((Integer) options.valueOf(MAX_THREADS)); if(options.has(SELECTORS)) config.setSelectors((Integer) options.valueOf(SELECTORS)); if(options.has(SOCKET_BUFFER_SIZE)) config.setSocketBufferSize((Integer) options.valueOf(SOCKET_BUFFER_SIZE)); config.setBootstrapUrls(url); ClientConnectionStressTest test = new ClientConnectionStressTest(config, storeName, config.getMaxThreads(), connsTotal, reqs); test.execute(); } }