Permalink
Browse files

Add simple stress tester tool

  • Loading branch information...
1 parent 57ea184 commit a607aac5da6d95ad6ca06eb2b6dda0ecb106cb70 @readams readams committed Jun 15, 2009
@@ -54,10 +54,10 @@ class SocketStoreClientFactory: public StoreClientFactory
virtual ~SocketStoreClientFactory();
// StoreClientFactory interface
- virtual StoreClient* getStoreClient(std::string& storeName);
- virtual StoreClient* getStoreClient(std::string& storeName,
+ virtual StoreClient* getStoreClient(const std::string& storeName);
+ virtual StoreClient* getStoreClient(const std::string& storeName,
shared_ptr<InconsistencyResolver>& resolver);
- virtual Store* getRawStore(std::string& storeName,
+ virtual Store* getRawStore(const std::string& storeName,
shared_ptr<InconsistencyResolver>& resolver);
private:
@@ -53,7 +53,7 @@ class StoreClientFactory
* @return A fully-constructed @ref StoreClient
* @see getStoreClient(std::string&, InconsistencyResolver*)
*/
- virtual StoreClient* getStoreClient(std::string& storeName) = 0;
+ virtual StoreClient* getStoreClient(const std::string& storeName) = 0;
/**
* Get a @ref StoreClient for the given store. Returns a newly
@@ -68,7 +68,7 @@ class StoreClientFactory
* @return A fully-constructed @ref StoreClient
* @see getStoreClient(std::string&)
*/
- virtual StoreClient* getStoreClient(std::string& storeName,
+ virtual StoreClient* getStoreClient(const std::string& storeName,
shared_ptr<InconsistencyResolver>& resolver) = 0;
/**
@@ -83,7 +83,7 @@ class StoreClientFactory
* time-based resolution scheme will be used.
* @return the appropriate store
*/
- virtual Store* getRawStore(std::string& storeName,
+ virtual Store* getRawStore(const std::string& storeName,
shared_ptr<InconsistencyResolver>& resolver) = 0;
};
@@ -205,21 +205,21 @@ SocketStoreClientFactory::~SocketStoreClientFactory() {
delete pimpl_;
}
-StoreClient* SocketStoreClientFactory::getStoreClient(std::string& storeName) {
+StoreClient* SocketStoreClientFactory::getStoreClient(const std::string& storeName) {
shared_ptr<InconsistencyResolver> nullResolver;
return getStoreClient(storeName, nullResolver);
}
StoreClient* SocketStoreClientFactory::
-getStoreClient(std::string& storeName,
+getStoreClient(const std::string& storeName,
shared_ptr<InconsistencyResolver>& resolver) {
shared_ptr<Store> store(getRawStore(storeName, resolver));
return new DefaultStoreClient(store,
pimpl_->config);
}
-Store* SocketStoreClientFactory::getRawStore(std::string& storeName,
+Store* SocketStoreClientFactory::getRawStore(const std::string& storeName,
shared_ptr<InconsistencyResolver>& resolver) {
VersionedValue clustervv = pimpl_->bootstrapMetadata(CLUSTER_KEY);
const std::string* clusterXml = clustervv.getValue();
@@ -1 +1,2 @@
voldemortShell
+stress
@@ -18,8 +18,10 @@
AM_CPPFLAGS = -I$(top_srcdir)/include
-bin_PROGRAMS = voldemortShell
+bin_PROGRAMS = voldemortShell stress
voldemortShell_SOURCES = voldemortShell.cpp
-
voldemortShell_LDADD = ../src/libvoldemort.la
+
+stress_SOURCES = stress.cpp
+stress_LDADD = ../src/libvoldemort.la
@@ -0,0 +1,140 @@
+/* -*- C++ -*-; c-basic-offset: 4; indent-tabs-mode: nil */
+/*
+ * Stress tester for Voldemort C++ client
+ *
+ * Copyright (c) 2009 Webroot Software, 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.
+ */
+
+#include <signal.h>
+#include <sys/time.h>
+#include <time.h>
+#include <memory>
+#include <vector>
+
+#include <voldemort/voldemort.h>
+#include <boost/thread/thread.hpp>
+#include <boost/shared_ptr.hpp>
+
+using namespace Voldemort;
+using namespace std;
+using namespace boost;
+
+const int STRESS_THREADS = 4;
+const string STORE_NAME("test");
+const string KEY("hello");
+
+volatile int continueStress = 1;
+
+class stresser
+{
+public:
+ stresser(shared_ptr<StoreClient>& client_,
+ int& count_)
+ : client(client_), count(count_) { }
+
+ void operator()() {
+ while (continueStress) {
+ client->get(&KEY);
+ count += 1;
+ }
+ }
+
+ shared_ptr<StoreClient> client;
+ int& count;
+};
+
+/* Halt tester threads on sigint */
+void handleSig(int sig) {
+ continueStress = 0;
+}
+
+int main(int argc, char** argv) {
+ if (argc < 2) {
+ cerr << "Usage: " << argv[0] << "{bootstrap URLs list}" << endl
+ << " URLs of the form tcp://host:port" << endl;
+ exit(1);
+ }
+
+ try {
+ // Initialize the bootstrap URLs. This is a list of server URLs
+ // in the cluster that we use to download metadata for the
+ // cluster. You only need one to be able to use the cluster, but
+ // more will increase availability when initializing.
+ list<string> bootstrapUrls;
+ for (int i = 1; i < argc; i++) {
+ bootstrapUrls.push_back(string(argv[i]));
+ }
+
+ // The store name is essentially a namespace on the Voldemort
+ // cluster
+ string storeName("test");
+
+ // The ClientConfig object allows you to configure settings on how
+ // we access the Voldemort cluster. The set of bootstrap URLs is
+ // the only thing that must be configured.
+ ClientConfig config;
+ config.setBootstrapUrls(&bootstrapUrls);
+
+ // We access the server using a StoreClient object. We create
+ // StoreClients using a StoreClientFactory. In this case we're
+ // using the SocketStoreClientFactory which will connect to a
+ // Voldemort cluster over TCP.
+ SocketStoreClientFactory factory(config);
+
+ vector<shared_ptr<StoreClient> > clients(STRESS_THREADS);
+ for (int i = 0; i < STRESS_THREADS; i++) {
+ shared_ptr<StoreClient> client(factory.getStoreClient(STORE_NAME));
+ clients[i] = client;
+ }
+ int counts[STRESS_THREADS];
+ memset(counts, 0, sizeof(int) * STRESS_THREADS);
+
+ struct timeval starttime;
+ struct timeval endtime;
+
+ // Start up stress threads
+ gettimeofday(&starttime, NULL);
+ thread_group group;
+ for (int i = 0; i < STRESS_THREADS; i++) {
+ group.create_thread(stresser(clients[i], counts[i]));
+ }
+
+ signal(SIGINT, handleSig);
+
+ // join stress threads
+ group.join_all();
+ gettimeofday(&endtime, NULL);
+
+ int total = 0;
+ for (int i = 0; i < STRESS_THREADS; i++) {
+ total += counts[i];
+ }
+ unsigned long time =
+ ((((unsigned long)endtime.tv_sec)*1000000L) +
+ (unsigned long)endtime.tv_usec) -
+ ((((unsigned long)starttime.tv_sec)*1000000L) +
+ (unsigned long)starttime.tv_usec);
+ time /= 1000;
+ double throughput = ((double)total) * (double)1000 / time;
+
+ cout << "Performed " << total << " ops in "
+ << ((double)time)/1000.0
+ << " seconds (" << throughput << " ops/sec)"
+ << endl;
+ } catch (VoldemortException& e) {
+ cerr << "Error while initializing: " << e.what() << endl;
+ exit(1);
+ }
+}
@@ -81,6 +81,12 @@ bool quitCommand(StoreClient* client, const vector<string>& tokens) {
}
int main(int argc, char** argv) {
+ if (argc < 2) {
+ cerr << "Usage: " << argv[0] << "{bootstrap URLs list}" << endl
+ << " URLs of the form tcp://host:port" << endl;
+ exit(1);
+ }
+
map<string, command> comMap;
comMap[string("get")] = getCommand;
comMap[string("put")] = putCommand;

0 comments on commit a607aac

Please sign in to comment.