perfkitbenchmarker/linux_benchmarks/jdbc_ycsb_benchmark.py (103 lines of code) (raw):
# Copyright 2016 PerfKitBenchmarker Authors. 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.
"""Run YCSB benchmark against managed SQL databases that support JDBC.
This benchmark does not provision VMs for the corresponding SQL database
cluster. The only VM group is client group that sends requests to specified
DB.
Before running this benchmark, you have to manually create `usertable` as
specified in YCSB JDBC binding.
Tested against Azure SQL database.
"""
import posixpath
from absl import flags
from perfkitbenchmarker import background_tasks
from perfkitbenchmarker import configs
from perfkitbenchmarker import errors
from perfkitbenchmarker.linux_packages import ycsb
BENCHMARK_NAME = 'jdbc_ycsb'
BENCHMARK_CONFIG = """
jdbc_ycsb:
description: >
Run YCSB against relational databases that support JDBC.
Configure the number of VMs via --num-vms.
vm_groups:
default:
os_type: ubuntu2204 # Python 2
vm_spec: *default_dual_core
vm_count: 1"""
YCSB_BINDING_LIB_DIR = posixpath.join(ycsb.YCSB_DIR, 'jdbc-binding', 'lib')
CREATE_TABLE_SQL = (
'CREATE TABLE usertable '
'(YCSB_KEY VARCHAR(255) PRIMARY KEY, '
'FIELD0 TEXT, FIELD1 TEXT, '
'FIELD2 TEXT, FIELD3 TEXT, '
'FIELD4 TEXT, FIELD5 TEXT, '
'FIELD6 TEXT, FIELD7 TEXT, '
'FIELD8 TEXT, FIELD9 TEXT);'
)
DROP_TABLE_SQL = 'DROP TABLE IF EXISTS usertable;'
FLAGS = flags.FLAGS
flags.DEFINE_string(
'jdbc_ycsb_db_driver', None, 'The class of JDBC driver that connects to DB.'
)
flags.DEFINE_string(
'jdbc_ycsb_db_url', None, 'The URL that is used to connect to DB'
)
flags.DEFINE_string('jdbc_ycsb_db_user', None, 'The username of target DB.')
flags.DEFINE_string(
'jdbc_ycsb_db_passwd', None, 'The password of specified DB user.'
)
flags.DEFINE_string(
'jdbc_ycsb_db_driver_path',
None,
'The path to JDBC driver jar file on local machine.',
)
flags.DEFINE_integer(
'jdbc_ycsb_db_batch_size', 0, 'The batch size for doing batched insert.'
)
flags.DEFINE_integer(
'jdbc_ycsb_fetch_size', 10, 'The JDBC fetch size hinted to driver'
)
def GetConfig(user_config):
config = configs.LoadConfig(BENCHMARK_CONFIG, user_config, BENCHMARK_NAME)
if FLAGS['ycsb_client_vms'].present:
config['vm_groups']['default']['vm_count'] = FLAGS.ycsb_client_vms
return config
def CheckPrerequisites(benchmark_config):
# Before YCSB Cloud Datastore supports Application Default Credential,
# we should always make sure valid credential flags are set.
if not FLAGS.jdbc_ycsb_db_driver:
raise ValueError('"jdbc_ycsb_db_driver" must be set')
if not FLAGS.jdbc_ycsb_db_driver_path:
raise ValueError('"jdbc_ycsb_db_driver_path" must be set')
if not FLAGS.jdbc_ycsb_db_url:
raise ValueError('"jdbc_ycsb_db_url" must be set')
if not FLAGS.jdbc_ycsb_db_user:
raise ValueError('"jdbc_ycsb_db_user" must be set ')
if not FLAGS.jdbc_ycsb_db_passwd:
raise ValueError('"jdbc_ycsb_db_passwd" must be set ')
def Prepare(benchmark_spec):
benchmark_spec.always_call_cleanup = True
vms = benchmark_spec.vms
# Install required packages and copy credential files.
background_tasks.RunThreaded(_Install, vms)
# Create benchmark table.
ExecuteSql(vms[0], DROP_TABLE_SQL)
ExecuteSql(vms[0], CREATE_TABLE_SQL)
benchmark_spec.executor = ycsb.YCSBExecutor('jdbc')
def ExecuteSql(vm, sql):
db_args = (
' -p db.driver={} -p db.url="{}" -p db.user={} -p db.passwd={}'
).format(
FLAGS.jdbc_ycsb_db_driver,
FLAGS.jdbc_ycsb_db_url,
FLAGS.jdbc_ycsb_db_user,
FLAGS.jdbc_ycsb_db_passwd,
)
exec_cmd = 'java -cp "{}/*" com.yahoo.ycsb.db.JdbcDBCli -c "{}" '.format(
YCSB_BINDING_LIB_DIR, sql
)
stdout, stderr = vm.RobustRemoteCommand(exec_cmd + db_args)
if 'successfully executed' not in stdout and not stderr:
raise errors.VirtualMachine.RemoteCommandError(stderr)
def Run(benchmark_spec):
vms = benchmark_spec.vms
run_kwargs = {
'db.driver': FLAGS.jdbc_ycsb_db_driver,
'db.url': '"%s"' % FLAGS.jdbc_ycsb_db_url,
'db.user': FLAGS.jdbc_ycsb_db_user,
'db.passwd': FLAGS.jdbc_ycsb_db_passwd,
'db.batchsize': FLAGS.jdbc_ycsb_db_batch_size,
'jdbc.fetchsize': FLAGS.jdbc_ycsb_fetch_size,
}
load_kwargs = run_kwargs.copy()
if FLAGS['ycsb_preload_threads'].present:
load_kwargs['threads'] = FLAGS['ycsb_preload_threads']
samples = list(
benchmark_spec.executor.LoadAndRun(
vms, load_kwargs=load_kwargs, run_kwargs=run_kwargs
)
)
return samples
def Cleanup(benchmark_spec):
# support automatic cleanup.
ExecuteSql(benchmark_spec.vms[0], DROP_TABLE_SQL)
def _Install(vm):
vm.Install('ycsb')
# Copy driver jar to VM.
vm.RemoteCopy(FLAGS.jdbc_ycsb_db_driver_path, YCSB_BINDING_LIB_DIR)