2012-02-19 05:07:33 +04:00
|
|
|
#!/usr/bin/env python
|
2015-08-06 03:08:01 +03:00
|
|
|
#
|
|
|
|
# Copyright (c) 2012 - 2015 YCSB contributors. All rights reserved.
|
|
|
|
#
|
|
|
|
# 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. See accompanying
|
|
|
|
# LICENSE file.
|
|
|
|
#
|
2012-02-19 05:07:33 +04:00
|
|
|
|
2015-12-08 17:33:07 +03:00
|
|
|
import errno
|
2015-06-26 10:31:50 +03:00
|
|
|
import fnmatch
|
2015-05-29 19:07:55 +03:00
|
|
|
import io
|
2012-02-19 05:07:33 +04:00
|
|
|
import os
|
2015-05-29 19:07:55 +03:00
|
|
|
import shlex
|
2012-02-19 05:07:33 +04:00
|
|
|
import sys
|
|
|
|
import subprocess
|
2015-12-08 17:33:07 +03:00
|
|
|
try:
|
|
|
|
import argparse
|
|
|
|
except ImportError:
|
|
|
|
print >> sys.stderr, '[ERROR] argparse not found. Try installing it via "pip".'
|
|
|
|
raise
|
2012-02-19 05:07:33 +04:00
|
|
|
|
2012-02-22 13:32:13 +04:00
|
|
|
BASE_URL = "https://github.com/brianfrankcooper/YCSB/tree/master/"
|
2012-02-19 05:07:33 +04:00
|
|
|
COMMANDS = {
|
2012-02-24 12:08:06 +04:00
|
|
|
"shell" : {
|
|
|
|
"command" : "",
|
|
|
|
"description" : "Interactive mode",
|
|
|
|
"main" : "com.yahoo.ycsb.CommandLine",
|
|
|
|
},
|
2012-02-19 10:28:56 +04:00
|
|
|
"load" : {
|
|
|
|
"command" : "-load",
|
|
|
|
"description" : "Execute the load phase",
|
2012-02-24 12:08:06 +04:00
|
|
|
"main" : "com.yahoo.ycsb.Client",
|
2012-02-19 10:28:56 +04:00
|
|
|
},
|
|
|
|
"run" : {
|
|
|
|
"command" : "-t",
|
|
|
|
"description" : "Execute the transaction phase",
|
2012-02-24 12:08:06 +04:00
|
|
|
"main" : "com.yahoo.ycsb.Client",
|
2012-02-19 10:28:56 +04:00
|
|
|
},
|
2012-02-19 05:07:33 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
DATABASES = {
|
2015-10-05 05:06:54 +03:00
|
|
|
"accumulo" : "com.yahoo.ycsb.db.accumulo.AccumuloClient",
|
2015-06-25 13:07:17 +03:00
|
|
|
"aerospike" : "com.yahoo.ycsb.db.AerospikeClient",
|
2012-02-19 10:28:56 +04:00
|
|
|
"basic" : "com.yahoo.ycsb.BasicDB",
|
|
|
|
"cassandra-7" : "com.yahoo.ycsb.db.CassandraClient7",
|
|
|
|
"cassandra-8" : "com.yahoo.ycsb.db.CassandraClient8",
|
|
|
|
"cassandra-10" : "com.yahoo.ycsb.db.CassandraClient10",
|
2013-10-17 01:59:56 +04:00
|
|
|
"cassandra-cql": "com.yahoo.ycsb.db.CassandraCQLClient",
|
2015-10-15 19:23:18 +03:00
|
|
|
"cassandra2-cql": "com.yahoo.ycsb.db.CassandraCQLClient",
|
2015-06-11 16:29:37 +03:00
|
|
|
"couchbase" : "com.yahoo.ycsb.db.CouchbaseClient",
|
2016-04-06 09:32:30 +03:00
|
|
|
"couchbase2" : "com.yahoo.ycsb.db.couchbase2.Couchbase2Client",
|
2012-08-03 06:09:30 +04:00
|
|
|
"dynamodb" : "com.yahoo.ycsb.db.DynamoDBClient",
|
2016-03-07 19:31:01 +03:00
|
|
|
"elasticsearch": "com.yahoo.ycsb.db.ElasticsearchClient",
|
2015-08-14 07:37:35 +03:00
|
|
|
"geode" : "com.yahoo.ycsb.db.GeodeClient",
|
2016-04-08 22:13:55 +03:00
|
|
|
"googlebigtable" : "com.yahoo.ycsb.db.GoogleBigtableClient",
|
2015-11-15 06:40:24 +03:00
|
|
|
"googledatastore" : "com.yahoo.ycsb.db.GoogleDatastoreClient",
|
2015-08-20 21:08:56 +03:00
|
|
|
"hbase094" : "com.yahoo.ycsb.db.HBaseClient",
|
|
|
|
"hbase098" : "com.yahoo.ycsb.db.HBaseClient",
|
|
|
|
"hbase10" : "com.yahoo.ycsb.db.HBaseClient10",
|
2012-07-10 00:38:55 +04:00
|
|
|
"hypertable" : "com.yahoo.ycsb.db.HypertableClient",
|
2015-04-21 08:52:36 +03:00
|
|
|
"infinispan-cs": "com.yahoo.ycsb.db.InfinispanRemoteClient",
|
2012-02-19 10:28:56 +04:00
|
|
|
"infinispan" : "com.yahoo.ycsb.db.InfinispanClient",
|
|
|
|
"jdbc" : "com.yahoo.ycsb.db.JdbcDBClient",
|
2015-10-08 01:05:13 +03:00
|
|
|
"kudu" : "com.yahoo.ycsb.db.KuduYCSBClient",
|
2012-02-19 10:28:56 +04:00
|
|
|
"mapkeeper" : "com.yahoo.ycsb.db.MapKeeperClient",
|
2015-11-27 23:09:01 +03:00
|
|
|
"memcached" : "com.yahoo.ycsb.db.MemcachedClient",
|
2012-02-19 10:28:56 +04:00
|
|
|
"mongodb" : "com.yahoo.ycsb.db.MongoDbClient",
|
2013-07-27 05:20:02 +04:00
|
|
|
"mongodb-async": "com.yahoo.ycsb.db.AsyncMongoDbClient",
|
2012-02-20 06:16:22 +04:00
|
|
|
"nosqldb" : "com.yahoo.ycsb.db.NoSqlDbClient",
|
2012-05-11 02:59:49 +04:00
|
|
|
"orientdb" : "com.yahoo.ycsb.db.OrientDBClient",
|
2015-05-29 19:07:55 +03:00
|
|
|
"redis" : "com.yahoo.ycsb.db.RedisClient",
|
2016-04-12 11:53:28 +03:00
|
|
|
"riak" : "com.yahoo.ycsb.db.riak.RiakKVClient",
|
2015-11-25 07:35:27 +03:00
|
|
|
"s3" : "com.yahoo.ycsb.db.S3Client",
|
[solr] adding support for Apache Solr
updating readme
updating package info
perfecting logic for http solr clients for all operations
renamed properties, tested cloud mode and cleaned code
removed dependency on dynamic field names, updated readme
now enforcing checkstyle
adding solr artifact
removing test cases relying on external dependencies
removed unused maven dependencies, added batch mode support, all try blocks now catch eplicit exceptions, Query/UpdateResponse status codes are handled more granularly, updated readme, added sample schema.xml file to support default field names in ycsb client, updated all license headers to 2016, using SolrClient object as primary client type regardless if Solr is running in Cloud or Stand-alone mode
cleaned code and config files, now accepting a solr base url property, simplified sample schema.xml file, renamed class to SolrClient, now updating documents atomically, added batch support to delete method
updated new line spacing of pom file comments
removed sample schema file, updated readme with more indepth explanation on running/setting up the solr-binding
removed some code lines no longer in use
renamed zookeeper param name, now throwing caught exceptions where appropriate, debug messages are now being logged on stderr
now returning an appropriate error if we receive an unexpected response from solr server, repeated calls to getResults is no longer
now using singletonMap to store update params in, fixed typo and missing id field in sample config in README
2015-12-30 20:20:46 +03:00
|
|
|
"solr" : "com.yahoo.ycsb.db.SolrClient",
|
2015-06-12 14:16:53 +03:00
|
|
|
"tarantool" : "com.yahoo.ycsb.db.TarantoolClient",
|
|
|
|
"voldemort" : "com.yahoo.ycsb.db.VoldemortClient"
|
2012-02-19 05:07:33 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
OPTIONS = {
|
2015-05-29 19:07:55 +03:00
|
|
|
"-P file" : "Specify workload file",
|
|
|
|
"-p key=value" : "Override workload property",
|
|
|
|
"-s" : "Print status to stderr",
|
|
|
|
"-target n" : "Target ops/sec (default: unthrottled)",
|
|
|
|
"-threads n" : "Number of client threads (default: 1)",
|
|
|
|
"-cp path" : "Additional Java classpath entries",
|
|
|
|
"-jvm-args args" : "Additional arguments to the JVM",
|
2012-02-19 05:07:33 +04:00
|
|
|
}
|
2012-02-19 13:05:07 +04:00
|
|
|
|
2012-02-19 05:07:33 +04:00
|
|
|
def usage():
|
2015-05-29 19:07:55 +03:00
|
|
|
output = io.BytesIO()
|
|
|
|
print >> output, "%s command database [options]" % sys.argv[0]
|
2012-02-19 05:07:33 +04:00
|
|
|
|
2015-05-29 19:07:55 +03:00
|
|
|
print >> output, "\nCommands:"
|
2012-02-19 05:07:33 +04:00
|
|
|
for command in sorted(COMMANDS.keys()):
|
2015-05-29 19:07:55 +03:00
|
|
|
print >> output, " %s %s" % (command.ljust(14),
|
|
|
|
COMMANDS[command]["description"])
|
2012-02-19 05:07:33 +04:00
|
|
|
|
2015-05-29 19:07:55 +03:00
|
|
|
print >> output, "\nDatabases:"
|
2012-02-19 05:07:33 +04:00
|
|
|
for db in sorted(DATABASES.keys()):
|
2015-05-29 19:07:55 +03:00
|
|
|
print >> output, " %s %s" % (db.ljust(14), BASE_URL +
|
|
|
|
db.split("-")[0])
|
2012-02-19 10:28:56 +04:00
|
|
|
|
2015-05-29 19:07:55 +03:00
|
|
|
print >> output, "\nOptions:"
|
2012-02-24 12:26:33 +04:00
|
|
|
for option in sorted(OPTIONS.keys()):
|
2015-05-29 19:07:55 +03:00
|
|
|
print >> output, " %s %s" % (option.ljust(14), OPTIONS[option])
|
2012-02-24 12:26:33 +04:00
|
|
|
|
2015-05-29 19:07:55 +03:00
|
|
|
print >> output, """\nWorkload Files:
|
2012-02-19 10:28:56 +04:00
|
|
|
There are various predefined workloads under workloads/ directory.
|
|
|
|
See https://github.com/brianfrankcooper/YCSB/wiki/Core-Properties
|
2012-02-19 13:05:07 +04:00
|
|
|
for the list of workload properties."""
|
2012-02-19 05:07:33 +04:00
|
|
|
|
2015-05-29 19:07:55 +03:00
|
|
|
return output.getvalue()
|
|
|
|
|
2015-12-08 17:33:07 +03:00
|
|
|
def check_output(cmd):
|
|
|
|
p = subprocess.Popen(cmd, stdout=subprocess.PIPE)
|
|
|
|
stdout, _ = p.communicate()
|
|
|
|
if p.returncode:
|
|
|
|
raise subprocess.CalledProcessError(p.returncode, cmd)
|
|
|
|
return stdout
|
|
|
|
|
2015-06-26 10:31:50 +03:00
|
|
|
def debug(message):
|
|
|
|
print >> sys.stderr, "[DEBUG] ", message
|
2012-02-19 05:07:33 +04:00
|
|
|
|
2015-06-26 10:31:50 +03:00
|
|
|
def warn(message):
|
|
|
|
print >> sys.stderr, "[WARN] ", message
|
|
|
|
|
|
|
|
def error(message):
|
|
|
|
print >> sys.stderr, "[ERROR] ", message
|
|
|
|
|
|
|
|
def find_jars(dir, glob='*.jar'):
|
2012-02-19 05:07:33 +04:00
|
|
|
jars = []
|
|
|
|
for (dirpath, dirnames, filenames) in os.walk(dir):
|
2015-06-26 10:31:50 +03:00
|
|
|
for filename in fnmatch.filter(filenames, glob):
|
|
|
|
jars.append(os.path.join(dirpath, filename))
|
2012-02-19 05:07:33 +04:00
|
|
|
return jars
|
|
|
|
|
|
|
|
def get_ycsb_home():
|
2012-02-19 06:48:24 +04:00
|
|
|
dir = os.path.abspath(os.path.dirname(sys.argv[0]))
|
2015-06-28 08:00:22 +03:00
|
|
|
while "LICENSE.txt" not in os.listdir(dir):
|
2012-02-19 06:48:24 +04:00
|
|
|
dir = os.path.join(dir, os.path.pardir)
|
2012-02-19 13:05:07 +04:00
|
|
|
return os.path.abspath(dir)
|
2012-02-19 05:07:33 +04:00
|
|
|
|
2015-06-26 10:31:50 +03:00
|
|
|
def is_distribution():
|
|
|
|
# If there's a top level pom, we're a source checkout. otherwise a dist artifact
|
|
|
|
return "pom.xml" not in os.listdir(get_ycsb_home())
|
|
|
|
|
|
|
|
# Run the maven dependency plugin to get the local jar paths.
|
|
|
|
# presumes maven can run, so should only be run on source checkouts
|
|
|
|
# will invoke the 'package' goal for the given binding in order to resolve intra-project deps
|
|
|
|
# presumes maven properly handles system-specific path separators
|
2015-10-15 04:01:06 +03:00
|
|
|
# Given module is full module name eg. 'core' or 'couchbase-binding'
|
|
|
|
def get_classpath_from_maven(module):
|
2015-06-26 10:31:50 +03:00
|
|
|
try:
|
2015-10-15 04:01:06 +03:00
|
|
|
debug("Running 'mvn -pl com.yahoo.ycsb:" + module + " -am package -DskipTests "
|
2015-06-26 10:31:50 +03:00
|
|
|
"dependency:build-classpath -DincludeScope=compile -Dmdep.outputFilterFile=true'")
|
2015-12-08 17:33:07 +03:00
|
|
|
mvn_output = check_output(["mvn", "-pl", "com.yahoo.ycsb:" + module,
|
|
|
|
"-am", "package", "-DskipTests",
|
|
|
|
"dependency:build-classpath",
|
|
|
|
"-DincludeScope=compile",
|
|
|
|
"-Dmdep.outputFilterFile=true"])
|
2015-06-26 10:31:50 +03:00
|
|
|
# the above outputs a "classpath=/path/tojar:/path/to/other/jar" for each module
|
|
|
|
# the last module will be the datastore binding
|
|
|
|
line = [x for x in mvn_output.splitlines() if x.startswith("classpath=")][-1:]
|
|
|
|
return line[0][len("classpath="):]
|
|
|
|
except subprocess.CalledProcessError, err:
|
|
|
|
error("Attempting to generate a classpath from Maven failed "
|
|
|
|
"with return code '" + str(err.returncode) + "'. The output from "
|
|
|
|
"Maven follows, try running "
|
|
|
|
"'mvn -DskipTests package dependency:build=classpath' on your "
|
|
|
|
"own and correct errors." + os.linesep + os.linesep + "mvn output:" + os.linesep
|
|
|
|
+ err.output)
|
|
|
|
sys.exit(err.returncode)
|
2015-05-29 19:07:55 +03:00
|
|
|
|
|
|
|
def main():
|
|
|
|
p = argparse.ArgumentParser(
|
|
|
|
usage=usage(),
|
|
|
|
formatter_class=argparse.RawDescriptionHelpFormatter)
|
|
|
|
p.add_argument('-cp', dest='classpath', help="""Additional classpath
|
|
|
|
entries, e.g. '-cp /tmp/hbase-1.0.1.1/conf'. Will be
|
|
|
|
prepended to the YCSB classpath.""")
|
|
|
|
p.add_argument("-jvm-args", default=[], type=shlex.split,
|
|
|
|
help="""Additional arguments to pass to 'java', e.g.
|
|
|
|
'-Xmx4g'""")
|
|
|
|
p.add_argument("command", choices=sorted(COMMANDS),
|
|
|
|
help="""Command to run.""")
|
|
|
|
p.add_argument("database", choices=sorted(DATABASES),
|
|
|
|
help="""Database to test.""")
|
|
|
|
args, remaining = p.parse_known_args()
|
|
|
|
ycsb_home = get_ycsb_home()
|
|
|
|
|
|
|
|
# Use JAVA_HOME to find java binary if set, otherwise just use PATH.
|
|
|
|
java = "java"
|
|
|
|
java_home = os.getenv("JAVA_HOME")
|
|
|
|
if java_home:
|
|
|
|
java = os.path.join(java_home, "bin", "java")
|
|
|
|
db_classname = DATABASES[args.database]
|
|
|
|
command = COMMANDS[args.command]["command"]
|
|
|
|
main_classname = COMMANDS[args.command]["main"]
|
2015-06-26 10:31:50 +03:00
|
|
|
|
|
|
|
# Classpath set up
|
|
|
|
binding = args.database.split("-")[0]
|
2015-12-17 20:00:46 +03:00
|
|
|
|
|
|
|
# Deprecation message for the entire cassandra-binding
|
|
|
|
if binding == "cassandra":
|
|
|
|
warn("The 'cassandra-7', 'cassandra-8', 'cassandra-10', and "
|
|
|
|
"cassandra-cql' clients are deprecated. If you are using "
|
|
|
|
"Cassandra 2.X try using the 'cassandra2-cql' client instead.")
|
|
|
|
|
2015-06-26 10:31:50 +03:00
|
|
|
if is_distribution():
|
|
|
|
db_dir = os.path.join(ycsb_home, binding + "-binding")
|
|
|
|
# include top-level conf for when we're a binding-specific artifact.
|
|
|
|
# If we add top-level conf to the general artifact, starting here
|
|
|
|
# will allow binding-specific conf to override (because it's prepended)
|
|
|
|
cp = [os.path.join(ycsb_home, "conf")]
|
|
|
|
cp.extend(find_jars(os.path.join(ycsb_home, "lib")))
|
|
|
|
cp.extend(find_jars(os.path.join(db_dir, "lib")))
|
|
|
|
else:
|
|
|
|
warn("Running against a source checkout. In order to get our runtime "
|
|
|
|
"dependencies we'll have to invoke Maven. Depending on the state "
|
|
|
|
"of your system, this may take ~30-45 seconds")
|
2015-10-14 05:49:59 +03:00
|
|
|
db_location = "core" if binding == "basic" else binding
|
|
|
|
project = "core" if binding == "basic" else binding + "-binding"
|
|
|
|
db_dir = os.path.join(ycsb_home, db_location)
|
2015-06-26 10:31:50 +03:00
|
|
|
# goes first so we can rely on side-effect of package
|
2015-10-14 05:49:59 +03:00
|
|
|
maven_says = get_classpath_from_maven(project)
|
2015-06-26 10:31:50 +03:00
|
|
|
# TODO when we have a version property, skip the glob
|
|
|
|
cp = find_jars(os.path.join(db_dir, "target"),
|
2015-10-14 05:49:59 +03:00
|
|
|
project + "*.jar")
|
2015-06-26 10:31:50 +03:00
|
|
|
# alredy in jar:jar:jar form
|
|
|
|
cp.append(maven_says)
|
|
|
|
cp.insert(0, os.path.join(db_dir, "conf"))
|
2015-06-20 03:32:17 +03:00
|
|
|
classpath = os.pathsep.join(cp)
|
2015-05-29 19:07:55 +03:00
|
|
|
if args.classpath:
|
|
|
|
classpath = os.pathsep.join([args.classpath, classpath])
|
|
|
|
|
|
|
|
ycsb_command = ([java] + args.jvm_args +
|
|
|
|
["-cp", classpath,
|
|
|
|
main_classname, "-db", db_classname] + remaining)
|
|
|
|
if command:
|
|
|
|
ycsb_command.append(command)
|
|
|
|
print >> sys.stderr, " ".join(ycsb_command)
|
2015-12-08 17:33:07 +03:00
|
|
|
try:
|
|
|
|
return subprocess.call(ycsb_command)
|
|
|
|
except OSError as e:
|
|
|
|
if e.errno == errno.ENOENT:
|
|
|
|
error('Command failed. Is java installed and on your PATH?')
|
|
|
|
return 1
|
|
|
|
else:
|
|
|
|
raise
|
2015-05-29 19:07:55 +03:00
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
sys.exit(main())
|