diff --git a/.github/workflows/postgresql-16-src-meson-perf.yml b/.github/workflows/postgresql-16-src-meson-perf.yml new file mode 100644 index 00000000..4284ca04 --- /dev/null +++ b/.github/workflows/postgresql-16-src-meson-perf.yml @@ -0,0 +1,121 @@ +name: Perf test +on: [pull_request] +permissions: + contents: write + pull-requests: write + repository-projects: write + +jobs: + build: + runs-on: ubuntu-22.04 + steps: + + + - name: Remove old postgres + run: | + sudo apt purge postgresql-client-common postgresql-common \ + postgresql postgresql* + sudo rm -rf /var/lib/postgresql /var/log/postgresql /etc/postgresql \ + /usr/lib/postgresql /usr/include/postgresql /usr/share/postgresql \ + /etc/postgresql + sudo rm -f /usr/bin/pg_config + + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install -y libreadline6-dev systemtap-sdt-dev \ + zlib1g-dev libssl-dev libpam0g-dev bison flex \ + libipc-run-perl -y docbook-xsl docbook-xsl libxml2 libxml2-utils \ + libxml2-dev libxslt-dev xsltproc libkrb5-dev libldap2-dev \ + libsystemd-dev gettext tcl-dev libperl-dev pkg-config clang-11 \ + llvm-11 llvm-11-dev libselinux1-dev python3-dev \ + uuid-dev liblz4-dev meson ninja-build libjson-c-dev \ + sysbench + sudo /usr/bin/perl -MCPAN -e 'install IPC::RUN' + sudo /usr/bin/perl -MCPAN -e 'install Text::Trim' + + - name: Clone postgres repository + uses: actions/checkout@v2 + with: + repository: 'postgres/postgres' + ref: 'a81e5516fa4bc53e332cb35eefe231147c0e1749' + path: 'src' + + - name: Clone postgres-tde-ext repository + uses: actions/checkout@v2 + with: + path: 'src/contrib/postgres-tde-ext' + + - name: Include postgres-tde-ext in meson build + run: | + echo "subdir('postgres-tde-ext')" >> src/contrib/meson.build + + - name: Build postgres + run: | + meson setup build --prefix `pwd`/../inst --buildtype=release + cd build && ninja && ninja install + working-directory: src + + - name: Test postgres-tde-ext + run: | + cp ../contrib/postgres-tde-ext/keyring.json /tmp/keyring.json + meson test --suite setup -v + meson test --suite postgres-tde-ext -v --num-processes 1 + working-directory: src/build + + - name: Report on test fail + uses: actions/upload-artifact@v2 + if: ${{ failure() }} + with: + name: Regressions diff and postgresql log + path: | + src/build/testrun/postgres-tde-ext/regress/ + retention-days: 3 + + - name: Setup test environment + run: | + bin/initdb -D data + echo "shared_preload_libraries = 'pg_tde'" >> data/postgresql.conf + echo "pg_tde.keyringConfigFile = '/tmp/keyring.json'" >> data/postgresql.conf + bin/pg_ctl -D data start + bin/createdb sbtest + bin/createdb sbtest2 + bin/createuser sbtest -s + bin/psql sbtest2 <<< "CREATE EXTENSION pg_tde;" + cp -r ../src/contrib/postgres-tde-ext/sysbench . + working-directory: inst + + - name: Run baseline performance tests + run: | + sysbench --db-driver=pgsql --threads=1 sysbench/oltp_insert.lua --tables=1 --table-size=10000 --pgsql-db=sbtest prepare + sysbench --db-driver=pgsql --threads=1 sysbench/oltp_read_only.lua --tables=1 --table-size=10000 --pgsql-db=sbtest run + sysbench --db-driver=pgsql --threads=1 sysbench/oltp_read_only.lua --tables=1 --table-size=10000 --pgsql-db=sbtest run | tee perf_norm + working-directory: inst + + - name: Run TDE performance tests + run: | + sysbench --db-driver=pgsql --threads=1 sysbench/oltp_common_tde.lua --tables=1 --table-size=10000 --pgsql-db=sbtest2 prepare + sysbench --db-driver=pgsql --threads=1 sysbench/oltp_read_only.lua --tables=1 --table-size=10000 --pgsql-db=sbtest2 run + sysbench --db-driver=pgsql --threads=1 sysbench/oltp_read_only.lua --tables=1 --table-size=10000 --pgsql-db=sbtest2 run | tee perf_tde + working-directory: inst + + - name: Print results + run: | + NORM_Q=$(cat perf_norm | grep 'total number of events' | cut -d ':' -f 2 | sed 's/ //g') + TDE_Q=$(cat perf_tde | grep 'total number of events' | cut -d ':' -f 2 | sed 's/ //g') + echo "Norm queries: $NORM_Q" + echo "TDE queries: $TDE_Q" + echo "Performance test results:" >> pr_perf_results + echo "Normal queries: $(cat perf_norm | grep 'total number of events' | cut -d ':' -f 2 | sed 's/ //g')" >> pr_perf_results + echo "TDE queries: $(cat perf_tde | grep 'total number of events' | cut -d ':' -f 2 | sed 's/ //g')" >> pr_perf_results + echo "Percentage: $(($TDE_Q*100/$NORM_Q))%" >> pr_perf_results + PERF_RESULT=$(cat pr_perf_results) + echo "PERF_RESULT<> $GITHUB_ENV + echo "$PERF_RESULT" >> $GITHUB_ENV + echo "EOF" >> $GITHUB_ENV + working-directory: inst + + - uses: actions/upload-artifact@v3 + with: + name: pr_perf_results + path: inst/pr_perf_results diff --git a/.github/workflows/postgresql-perf-results.yml b/.github/workflows/postgresql-perf-results.yml new file mode 100644 index 00000000..ad425d98 --- /dev/null +++ b/.github/workflows/postgresql-perf-results.yml @@ -0,0 +1,51 @@ +name: Perf test results + +on: + workflow_run: + workflows: [Perf test] + types: + - completed + +jobs: + download: + runs-on: ubuntu-latest + steps: + - name: 'Download artifact' + uses: actions/github-script@v5 + with: + script: | + let allArtifacts = await github.rest.actions.listWorkflowRunArtifacts({ + owner: context.repo.owner, + repo: context.repo.repo, + run_id: context.payload.workflow_run.id, + }); + let matchArtifact = allArtifacts.data.artifacts.filter((artifact) => { + return artifact.name == "pr_perf_results" + })[0]; + let download = await github.rest.actions.downloadArtifact({ + owner: context.repo.owner, + repo: context.repo.repo, + artifact_id: matchArtifact.id, + archive_format: 'zip', + }); + let fs = require('fs'); + fs.writeFileSync(`${process.env.GITHUB_WORKSPACE}/pr_perf_results.zip`, Buffer.from(download.data)); + + - name: 'Unzip artifact' + run: | + unzip pr_perf_results.zip + + - name: Clone postgres-tde-ext repository + uses: actions/checkout@v2 + with: + path: 'src' + ref: ${{ github.event.workflow_run.head_branch }} + + - name: 'Create comment' + run: | + gh pr comment ${PR_NUMBER} -F ../pr_perf_results --edit-last || \ + gh pr comment ${PR_NUMBER} -F ../pr_perf_results + env: + PR_NUMBER: ${{ github.event.number }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + working-directory: src diff --git a/src/include/pg_tde_defines.h b/src/include/pg_tde_defines.h index 2c298595..7a000e66 100644 --- a/src/include/pg_tde_defines.h +++ b/src/include/pg_tde_defines.h @@ -19,9 +19,9 @@ * ---------- */ -#define ENCRYPTION_DEBUG 1 -#define KEYRING_DEBUG 1 -#define TDE_FORK_DEBUG 1 +#define ENCRYPTION_DEBUG 0 +#define KEYRING_DEBUG 0 +#define TDE_FORK_DEBUG 0 #define pg_tde_fill_tuple heap_fill_tuple #define pg_tde_form_tuple heap_form_tuple diff --git a/sysbench/bulk_insert.lua b/sysbench/bulk_insert.lua new file mode 100755 index 00000000..8be93bfb --- /dev/null +++ b/sysbench/bulk_insert.lua @@ -0,0 +1,56 @@ +#!/usr/bin/sysbench +-- -------------------------------------------------------------------------- -- +-- Bulk insert benchmark: do multi-row INSERTs concurrently in --threads +-- threads with each thread inserting into its own table. The number of INSERTs +-- executed by each thread is controlled by either --time or --events. +-- -------------------------------------------------------------------------- -- + +cursize=0 + +function thread_init() + drv = sysbench.sql.driver() + con = drv:connect() +end + +function prepare() + local i + + local drv = sysbench.sql.driver() + local con = drv:connect() + + for i = 1, sysbench.opt.threads do + print("Creating table 'sbtest" .. i .. "'...") + con:query(string.format([[ + CREATE TABLE IF NOT EXISTS sbtest%d ( + id INTEGER NOT NULL, + k INTEGER DEFAULT '0' NOT NULL, + PRIMARY KEY (id))]], i)) + end +end + +function event() + if (cursize == 0) then + con:bulk_insert_init("INSERT INTO sbtest" .. thread_id+1 .. " VALUES") + end + + cursize = cursize + 1 + + con:bulk_insert_next("(" .. cursize .. "," .. cursize .. ")") +end + +function thread_done(thread_9d) + con:bulk_insert_done() + con:disconnect() +end + +function cleanup() + local i + + local drv = sysbench.sql.driver() + local con = drv:connect() + + for i = 1, sysbench.opt.threads do + print("Dropping table 'sbtest" .. i .. "'...") + con:query("DROP TABLE IF EXISTS sbtest" .. i ) + end +end diff --git a/sysbench/oltp_common.lua b/sysbench/oltp_common.lua new file mode 100644 index 00000000..c42d432e --- /dev/null +++ b/sysbench/oltp_common.lua @@ -0,0 +1,503 @@ +-- Copyright (C) 2006-2018 Alexey Kopytov + +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; either version 2 of the License, or +-- (at your option) any later version. + +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. + +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +-- ----------------------------------------------------------------------------- +-- Common code for OLTP benchmarks. +-- ----------------------------------------------------------------------------- + +function init() + assert(event ~= nil, + "this script is meant to be included by other OLTP scripts and " .. + "should not be called directly.") +end + +if sysbench.cmdline.command == nil then + error("Command is required. Supported commands: prepare, prewarm, run, " .. + "cleanup, help") +end + +-- Command line options +sysbench.cmdline.options = { + table_size = + {"Number of rows per table", 10000}, + range_size = + {"Range size for range SELECT queries", 100}, + tables = + {"Number of tables", 1}, + point_selects = + {"Number of point SELECT queries per transaction", 10}, + simple_ranges = + {"Number of simple range SELECT queries per transaction", 1}, + sum_ranges = + {"Number of SELECT SUM() queries per transaction", 1}, + order_ranges = + {"Number of SELECT ORDER BY queries per transaction", 1}, + distinct_ranges = + {"Number of SELECT DISTINCT queries per transaction", 1}, + index_updates = + {"Number of UPDATE index queries per transaction", 1}, + non_index_updates = + {"Number of UPDATE non-index queries per transaction", 1}, + delete_inserts = + {"Number of DELETE/INSERT combinations per transaction", 1}, + range_selects = + {"Enable/disable all range SELECT queries", true}, + auto_inc = + {"Use AUTO_INCREMENT column as Primary Key (for MySQL), " .. + "or its alternatives in other DBMS. When disabled, use " .. + "client-generated IDs", true}, + skip_trx = + {"Don't start explicit transactions and execute all queries " .. + "in the AUTOCOMMIT mode", false}, + secondary = + {"Use a secondary index in place of the PRIMARY KEY", false}, + create_secondary = + {"Create a secondary index in addition to the PRIMARY KEY", true}, + mysql_storage_engine = + {"Storage engine, if MySQL is used", "innodb"}, + pgsql_variant = + {"Use this PostgreSQL variant when running with the " .. + "PostgreSQL driver. The only currently supported " .. + "variant is 'redshift'. When enabled, " .. + "create_secondary is automatically disabled, and " .. + "delete_inserts is set to 0"} +} + +-- Prepare the dataset. This command supports parallel execution, i.e. will +-- benefit from executing with --threads > 1 as long as --tables > 1 +function cmd_prepare() + local drv = sysbench.sql.driver() + local con = drv:connect() + + for i = sysbench.tid % sysbench.opt.threads + 1, sysbench.opt.tables, + sysbench.opt.threads do + create_table(drv, con, i) + end +end + +-- Preload the dataset into the server cache. This command supports parallel +-- execution, i.e. will benefit from executing with --threads > 1 as long as +-- --tables > 1 +-- +-- PS. Currently, this command is only meaningful for MySQL/InnoDB benchmarks +function cmd_prewarm() + local drv = sysbench.sql.driver() + local con = drv:connect() + + assert(drv:name() == "mysql", "prewarm is currently MySQL only") + + -- Do not create on disk tables for subsequent queries + con:query("SET tmp_table_size=2*1024*1024*1024") + con:query("SET max_heap_table_size=2*1024*1024*1024") + + for i = sysbench.tid % sysbench.opt.threads + 1, sysbench.opt.tables, + sysbench.opt.threads do + local t = "sbtest" .. i + print("Prewarming table " .. t) + con:query("ANALYZE TABLE sbtest" .. i) + con:query(string.format( + "SELECT AVG(id) FROM " .. + "(SELECT * FROM %s FORCE KEY (PRIMARY) " .. + "LIMIT %u) t", + t, sysbench.opt.table_size)) + con:query(string.format( + "SELECT COUNT(*) FROM " .. + "(SELECT * FROM %s WHERE k LIKE '%%0%%' LIMIT %u) t", + t, sysbench.opt.table_size)) + end +end + +-- Implement parallel prepare and prewarm commands +sysbench.cmdline.commands = { + prepare = {cmd_prepare, sysbench.cmdline.PARALLEL_COMMAND}, + prewarm = {cmd_prewarm, sysbench.cmdline.PARALLEL_COMMAND} +} + + +-- Template strings of random digits with 11-digit groups separated by dashes + +-- 10 groups, 119 characters +local c_value_template = "###########-###########-###########-" .. + "###########-###########-###########-" .. + "###########-###########-###########-" .. + "###########" + +-- 5 groups, 59 characters +local pad_value_template = "###########-###########-###########-" .. + "###########-###########" + +function get_c_value() + return sysbench.rand.string(c_value_template) +end + +function get_pad_value() + return sysbench.rand.string(pad_value_template) +end + +function create_table(drv, con, table_num) + local id_index_def, id_def + local engine_def = "" + local extra_table_options = "" + local query + + if sysbench.opt.secondary then + id_index_def = "KEY xid" + else + id_index_def = "PRIMARY KEY" + end + + if drv:name() == "mysql" or drv:name() == "attachsql" or + drv:name() == "drizzle" + then + if sysbench.opt.auto_inc then + id_def = "INTEGER NOT NULL AUTO_INCREMENT" + else + id_def = "INTEGER NOT NULL" + end + engine_def = "/*! ENGINE = " .. sysbench.opt.mysql_storage_engine .. " */" + extra_table_options = mysql_table_options or "" + elseif drv:name() == "pgsql" + then + if not sysbench.opt.auto_inc then + id_def = "INTEGER NOT NULL" + elseif pgsql_variant == 'redshift' then + id_def = "INTEGER IDENTITY(1,1)" + else + id_def = "SERIAL" + end + else + error("Unsupported database driver:" .. drv:name()) + end + + print(string.format("Creating table 'sbtest%d'...", table_num)) + + query = string.format([[ +CREATE TABLE sbtest%d( + id %s, + k INTEGER DEFAULT '0' NOT NULL, + c CHAR(120) DEFAULT '' NOT NULL, + pad CHAR(60) DEFAULT '' NOT NULL, + %s (id) +), + table_num, id_def, id_index_def, engine_def, extra_table_options) + + con:query(query) + + if (sysbench.opt.table_size > 0) then + print(string.format("Inserting %d records into 'sbtest%d'", + sysbench.opt.table_size, table_num)) + end + + if sysbench.opt.auto_inc then + query = "INSERT INTO sbtest" .. table_num .. "(k, c, pad) VALUES" + else + query = "INSERT INTO sbtest" .. table_num .. "(id, k, c, pad) VALUES" + end + + con:bulk_insert_init(query) + + local c_val + local pad_val + + for i = 1, sysbench.opt.table_size do + + c_val = get_c_value() + pad_val = get_pad_value() + + if (sysbench.opt.auto_inc) then + query = string.format("(%d, '%s', '%s')", + sb_rand(1, sysbench.opt.table_size), c_val, + pad_val) + else + query = string.format("(%d, %d, '%s', '%s')", + i, sb_rand(1, sysbench.opt.table_size), c_val, + pad_val) + end + + con:bulk_insert_next(query) + end + + con:bulk_insert_done() + + if sysbench.opt.create_secondary then + print(string.format("Creating a secondary index on 'sbtest%d'...", + table_num)) + con:query(string.format("CREATE INDEX k_%d ON sbtest%d(k)", + table_num, table_num)) + end +end + +local t = sysbench.sql.type +local stmt_defs = { + point_selects = { + "SELECT c FROM sbtest%u WHERE id=?", + t.INT}, + simple_ranges = { + "SELECT c FROM sbtest%u WHERE id BETWEEN ? AND ?", + t.INT, t.INT}, + sum_ranges = { + "SELECT SUM(k) FROM sbtest%u WHERE id BETWEEN ? AND ?", + t.INT, t.INT}, + order_ranges = { + "SELECT c FROM sbtest%u WHERE id BETWEEN ? AND ? ORDER BY c", + t.INT, t.INT}, + distinct_ranges = { + "SELECT DISTINCT c FROM sbtest%u WHERE id BETWEEN ? AND ? ORDER BY c", + t.INT, t.INT}, + index_updates = { + "UPDATE sbtest%u SET k=k+1 WHERE id=?", + t.INT}, + non_index_updates = { + "UPDATE sbtest%u SET c=? WHERE id=?", + {t.CHAR, 120}, t.INT}, + deletes = { + "DELETE FROM sbtest%u WHERE id=?", + t.INT}, + inserts = { + "INSERT INTO sbtest%u (id, k, c, pad) VALUES (?, ?, ?, ?)", + t.INT, t.INT, {t.CHAR, 120}, {t.CHAR, 60}}, +} + +function prepare_begin() + stmt.begin = con:prepare("BEGIN") +end + +function prepare_commit() + stmt.commit = con:prepare("COMMIT") +end + +function prepare_for_each_table(key) + for t = 1, sysbench.opt.tables do + stmt[t][key] = con:prepare(string.format(stmt_defs[key][1], t)) + + local nparam = #stmt_defs[key] - 1 + + if nparam > 0 then + param[t][key] = {} + end + + for p = 1, nparam do + local btype = stmt_defs[key][p+1] + local len + + if type(btype) == "table" then + len = btype[2] + btype = btype[1] + end + if btype == sysbench.sql.type.VARCHAR or + btype == sysbench.sql.type.CHAR then + param[t][key][p] = stmt[t][key]:bind_create(btype, len) + else + param[t][key][p] = stmt[t][key]:bind_create(btype) + end + end + + if nparam > 0 then + stmt[t][key]:bind_param(unpack(param[t][key])) + end + end +end + +function prepare_point_selects() + prepare_for_each_table("point_selects") +end + +function prepare_simple_ranges() + prepare_for_each_table("simple_ranges") +end + +function prepare_sum_ranges() + prepare_for_each_table("sum_ranges") +end + +function prepare_order_ranges() + prepare_for_each_table("order_ranges") +end + +function prepare_distinct_ranges() + prepare_for_each_table("distinct_ranges") +end + +function prepare_index_updates() + prepare_for_each_table("index_updates") +end + +function prepare_non_index_updates() + prepare_for_each_table("non_index_updates") +end + +function prepare_delete_inserts() + prepare_for_each_table("deletes") + prepare_for_each_table("inserts") +end + +function thread_init() + drv = sysbench.sql.driver() + con = drv:connect() + + -- Create global nested tables for prepared statements and their + -- parameters. We need a statement and a parameter set for each combination + -- of connection/table/query + stmt = {} + param = {} + + for t = 1, sysbench.opt.tables do + stmt[t] = {} + param[t] = {} + end + + -- This function is a 'callback' defined by individual benchmark scripts + prepare_statements() +end + +-- Close prepared statements +function close_statements() + for t = 1, sysbench.opt.tables do + for k, s in pairs(stmt[t]) do + stmt[t][k]:close() + end + end + if (stmt.begin ~= nil) then + stmt.begin:close() + end + if (stmt.commit ~= nil) then + stmt.commit:close() + end +end + +function thread_done() + close_statements() + con:disconnect() +end + +function cleanup() + local drv = sysbench.sql.driver() + local con = drv:connect() + + for i = 1, sysbench.opt.tables do + print(string.format("Dropping table 'sbtest%d'...", i)) + con:query("DROP TABLE IF EXISTS sbtest" .. i ) + end +end + +local function get_table_num() + return sysbench.rand.uniform(1, sysbench.opt.tables) +end + +local function get_id() + return sysbench.rand.default(1, sysbench.opt.table_size) +end + +function begin() + stmt.begin:execute() +end + +function commit() + stmt.commit:execute() +end + +function execute_point_selects() + local tnum = get_table_num() + local i + + for i = 1, sysbench.opt.point_selects do + param[tnum].point_selects[1]:set(get_id()) + + stmt[tnum].point_selects:execute() + end +end + +local function execute_range(key) + local tnum = get_table_num() + + for i = 1, sysbench.opt[key] do + local id = get_id() + + param[tnum][key][1]:set(id) + param[tnum][key][2]:set(id + sysbench.opt.range_size - 1) + + stmt[tnum][key]:execute() + end +end + +function execute_simple_ranges() + execute_range("simple_ranges") +end + +function execute_sum_ranges() + execute_range("sum_ranges") +end + +function execute_order_ranges() + execute_range("order_ranges") +end + +function execute_distinct_ranges() + execute_range("distinct_ranges") +end + +function execute_index_updates() + local tnum = get_table_num() + + for i = 1, sysbench.opt.index_updates do + param[tnum].index_updates[1]:set(get_id()) + + stmt[tnum].index_updates:execute() + end +end + +function execute_non_index_updates() + local tnum = get_table_num() + + for i = 1, sysbench.opt.non_index_updates do + param[tnum].non_index_updates[1]:set_rand_str(c_value_template) + param[tnum].non_index_updates[2]:set(get_id()) + + stmt[tnum].non_index_updates:execute() + end +end + +function execute_delete_inserts() + local tnum = get_table_num() + + for i = 1, sysbench.opt.delete_inserts do + local id = get_id() + local k = get_id() + + param[tnum].deletes[1]:set(id) + + param[tnum].inserts[1]:set(id) + param[tnum].inserts[2]:set(k) + param[tnum].inserts[3]:set_rand_str(c_value_template) + param[tnum].inserts[4]:set_rand_str(pad_value_template) + + stmt[tnum].deletes:execute() + stmt[tnum].inserts:execute() + end +end + +-- Re-prepare statements if we have reconnected, which is possible when some of +-- the listed error codes are in the --mysql-ignore-errors list +function sysbench.hooks.before_restart_event(errdesc) + if errdesc.sql_errno == 2013 or -- CR_SERVER_LOST + errdesc.sql_errno == 2055 or -- CR_SERVER_LOST_EXTENDED + errdesc.sql_errno == 2006 or -- CR_SERVER_GONE_ERROR + errdesc.sql_errno == 2011 -- CR_TCP_CONNECTION + then + close_statements() + prepare_statements() + end +end diff --git a/sysbench/oltp_common_tde.lua b/sysbench/oltp_common_tde.lua new file mode 100644 index 00000000..2973c0f7 --- /dev/null +++ b/sysbench/oltp_common_tde.lua @@ -0,0 +1,503 @@ +-- Copyright (C) 2006-2018 Alexey Kopytov + +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; either version 2 of the License, or +-- (at your option) any later version. + +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. + +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +-- ----------------------------------------------------------------------------- +-- Common code for OLTP benchmarks. +-- ----------------------------------------------------------------------------- + +function init() + assert(event ~= nil, + "this script is meant to be included by other OLTP scripts and " .. + "should not be called directly.") +end + +if sysbench.cmdline.command == nil then + error("Command is required. Supported commands: prepare, prewarm, run, " .. + "cleanup, help") +end + +-- Command line options +sysbench.cmdline.options = { + table_size = + {"Number of rows per table", 10000}, + range_size = + {"Range size for range SELECT queries", 100}, + tables = + {"Number of tables", 1}, + point_selects = + {"Number of point SELECT queries per transaction", 10}, + simple_ranges = + {"Number of simple range SELECT queries per transaction", 1}, + sum_ranges = + {"Number of SELECT SUM() queries per transaction", 1}, + order_ranges = + {"Number of SELECT ORDER BY queries per transaction", 1}, + distinct_ranges = + {"Number of SELECT DISTINCT queries per transaction", 1}, + index_updates = + {"Number of UPDATE index queries per transaction", 1}, + non_index_updates = + {"Number of UPDATE non-index queries per transaction", 1}, + delete_inserts = + {"Number of DELETE/INSERT combinations per transaction", 1}, + range_selects = + {"Enable/disable all range SELECT queries", true}, + auto_inc = + {"Use AUTO_INCREMENT column as Primary Key (for MySQL), " .. + "or its alternatives in other DBMS. When disabled, use " .. + "client-generated IDs", true}, + skip_trx = + {"Don't start explicit transactions and execute all queries " .. + "in the AUTOCOMMIT mode", false}, + secondary = + {"Use a secondary index in place of the PRIMARY KEY", false}, + create_secondary = + {"Create a secondary index in addition to the PRIMARY KEY", true}, + mysql_storage_engine = + {"Storage engine, if MySQL is used", "innodb"}, + pgsql_variant = + {"Use this PostgreSQL variant when running with the " .. + "PostgreSQL driver. The only currently supported " .. + "variant is 'redshift'. When enabled, " .. + "create_secondary is automatically disabled, and " .. + "delete_inserts is set to 0"} +} + +-- Prepare the dataset. This command supports parallel execution, i.e. will +-- benefit from executing with --threads > 1 as long as --tables > 1 +function cmd_prepare() + local drv = sysbench.sql.driver() + local con = drv:connect() + + for i = sysbench.tid % sysbench.opt.threads + 1, sysbench.opt.tables, + sysbench.opt.threads do + create_table(drv, con, i) + end +end + +-- Preload the dataset into the server cache. This command supports parallel +-- execution, i.e. will benefit from executing with --threads > 1 as long as +-- --tables > 1 +-- +-- PS. Currently, this command is only meaningful for MySQL/InnoDB benchmarks +function cmd_prewarm() + local drv = sysbench.sql.driver() + local con = drv:connect() + + assert(drv:name() == "mysql", "prewarm is currently MySQL only") + + -- Do not create on disk tables for subsequent queries + con:query("SET tmp_table_size=2*1024*1024*1024") + con:query("SET max_heap_table_size=2*1024*1024*1024") + + for i = sysbench.tid % sysbench.opt.threads + 1, sysbench.opt.tables, + sysbench.opt.threads do + local t = "sbtest" .. i + print("Prewarming table " .. t) + con:query("ANALYZE TABLE sbtest" .. i) + con:query(string.format( + "SELECT AVG(id) FROM " .. + "(SELECT * FROM %s FORCE KEY (PRIMARY) " .. + "LIMIT %u) t", + t, sysbench.opt.table_size)) + con:query(string.format( + "SELECT COUNT(*) FROM " .. + "(SELECT * FROM %s WHERE k LIKE '%%0%%' LIMIT %u) t", + t, sysbench.opt.table_size)) + end +end + +-- Implement parallel prepare and prewarm commands +sysbench.cmdline.commands = { + prepare = {cmd_prepare, sysbench.cmdline.PARALLEL_COMMAND}, + prewarm = {cmd_prewarm, sysbench.cmdline.PARALLEL_COMMAND} +} + + +-- Template strings of random digits with 11-digit groups separated by dashes + +-- 10 groups, 119 characters +local c_value_template = "###########-###########-###########-" .. + "###########-###########-###########-" .. + "###########-###########-###########-" .. + "###########" + +-- 5 groups, 59 characters +local pad_value_template = "###########-###########-###########-" .. + "###########-###########" + +function get_c_value() + return sysbench.rand.string(c_value_template) +end + +function get_pad_value() + return sysbench.rand.string(pad_value_template) +end + +function create_table(drv, con, table_num) + local id_index_def, id_def + local engine_def = "" + local extra_table_options = "" + local query + + if sysbench.opt.secondary then + id_index_def = "KEY xid" + else + id_index_def = "PRIMARY KEY" + end + + if drv:name() == "mysql" or drv:name() == "attachsql" or + drv:name() == "drizzle" + then + if sysbench.opt.auto_inc then + id_def = "INTEGER NOT NULL AUTO_INCREMENT" + else + id_def = "INTEGER NOT NULL" + end + engine_def = "/*! ENGINE = " .. sysbench.opt.mysql_storage_engine .. " */" + extra_table_options = mysql_table_options or "" + elseif drv:name() == "pgsql" + then + if not sysbench.opt.auto_inc then + id_def = "INTEGER NOT NULL" + elseif pgsql_variant == 'redshift' then + id_def = "INTEGER IDENTITY(1,1)" + else + id_def = "SERIAL" + end + else + error("Unsupported database driver:" .. drv:name()) + end + + print(string.format("Creating table 'sbtest%d'...", table_num)) + + query = string.format([[ +CREATE TABLE sbtest%d( + id %s, + k INTEGER DEFAULT '0' NOT NULL, + c CHAR(120) DEFAULT '' NOT NULL, + pad CHAR(60) DEFAULT '' NOT NULL, + %s (id) +) USING pg_tde %s %s]], + table_num, id_def, id_index_def, engine_def, extra_table_options) + + con:query(query) + + if (sysbench.opt.table_size > 0) then + print(string.format("Inserting %d records into 'sbtest%d'", + sysbench.opt.table_size, table_num)) + end + + if sysbench.opt.auto_inc then + query = "INSERT INTO sbtest" .. table_num .. "(k, c, pad) VALUES" + else + query = "INSERT INTO sbtest" .. table_num .. "(id, k, c, pad) VALUES" + end + + con:bulk_insert_init(query) + + local c_val + local pad_val + + for i = 1, sysbench.opt.table_size do + + c_val = get_c_value() + pad_val = get_pad_value() + + if (sysbench.opt.auto_inc) then + query = string.format("(%d, '%s', '%s')", + sb_rand(1, sysbench.opt.table_size), c_val, + pad_val) + else + query = string.format("(%d, %d, '%s', '%s')", + i, sb_rand(1, sysbench.opt.table_size), c_val, + pad_val) + end + + con:bulk_insert_next(query) + end + + con:bulk_insert_done() + + if sysbench.opt.create_secondary then + print(string.format("Creating a secondary index on 'sbtest%d'...", + table_num)) + con:query(string.format("CREATE INDEX k_%d ON sbtest%d(k)", + table_num, table_num)) + end +end + +local t = sysbench.sql.type +local stmt_defs = { + point_selects = { + "SELECT c FROM sbtest%u WHERE id=?", + t.INT}, + simple_ranges = { + "SELECT c FROM sbtest%u WHERE id BETWEEN ? AND ?", + t.INT, t.INT}, + sum_ranges = { + "SELECT SUM(k) FROM sbtest%u WHERE id BETWEEN ? AND ?", + t.INT, t.INT}, + order_ranges = { + "SELECT c FROM sbtest%u WHERE id BETWEEN ? AND ? ORDER BY c", + t.INT, t.INT}, + distinct_ranges = { + "SELECT DISTINCT c FROM sbtest%u WHERE id BETWEEN ? AND ? ORDER BY c", + t.INT, t.INT}, + index_updates = { + "UPDATE sbtest%u SET k=k+1 WHERE id=?", + t.INT}, + non_index_updates = { + "UPDATE sbtest%u SET c=? WHERE id=?", + {t.CHAR, 120}, t.INT}, + deletes = { + "DELETE FROM sbtest%u WHERE id=?", + t.INT}, + inserts = { + "INSERT INTO sbtest%u (id, k, c, pad) VALUES (?, ?, ?, ?)", + t.INT, t.INT, {t.CHAR, 120}, {t.CHAR, 60}}, +} + +function prepare_begin() + stmt.begin = con:prepare("BEGIN") +end + +function prepare_commit() + stmt.commit = con:prepare("COMMIT") +end + +function prepare_for_each_table(key) + for t = 1, sysbench.opt.tables do + stmt[t][key] = con:prepare(string.format(stmt_defs[key][1], t)) + + local nparam = #stmt_defs[key] - 1 + + if nparam > 0 then + param[t][key] = {} + end + + for p = 1, nparam do + local btype = stmt_defs[key][p+1] + local len + + if type(btype) == "table" then + len = btype[2] + btype = btype[1] + end + if btype == sysbench.sql.type.VARCHAR or + btype == sysbench.sql.type.CHAR then + param[t][key][p] = stmt[t][key]:bind_create(btype, len) + else + param[t][key][p] = stmt[t][key]:bind_create(btype) + end + end + + if nparam > 0 then + stmt[t][key]:bind_param(unpack(param[t][key])) + end + end +end + +function prepare_point_selects() + prepare_for_each_table("point_selects") +end + +function prepare_simple_ranges() + prepare_for_each_table("simple_ranges") +end + +function prepare_sum_ranges() + prepare_for_each_table("sum_ranges") +end + +function prepare_order_ranges() + prepare_for_each_table("order_ranges") +end + +function prepare_distinct_ranges() + prepare_for_each_table("distinct_ranges") +end + +function prepare_index_updates() + prepare_for_each_table("index_updates") +end + +function prepare_non_index_updates() + prepare_for_each_table("non_index_updates") +end + +function prepare_delete_inserts() + prepare_for_each_table("deletes") + prepare_for_each_table("inserts") +end + +function thread_init() + drv = sysbench.sql.driver() + con = drv:connect() + + -- Create global nested tables for prepared statements and their + -- parameters. We need a statement and a parameter set for each combination + -- of connection/table/query + stmt = {} + param = {} + + for t = 1, sysbench.opt.tables do + stmt[t] = {} + param[t] = {} + end + + -- This function is a 'callback' defined by individual benchmark scripts + prepare_statements() +end + +-- Close prepared statements +function close_statements() + for t = 1, sysbench.opt.tables do + for k, s in pairs(stmt[t]) do + stmt[t][k]:close() + end + end + if (stmt.begin ~= nil) then + stmt.begin:close() + end + if (stmt.commit ~= nil) then + stmt.commit:close() + end +end + +function thread_done() + close_statements() + con:disconnect() +end + +function cleanup() + local drv = sysbench.sql.driver() + local con = drv:connect() + + for i = 1, sysbench.opt.tables do + print(string.format("Dropping table 'sbtest%d'...", i)) + con:query("DROP TABLE IF EXISTS sbtest" .. i ) + end +end + +local function get_table_num() + return sysbench.rand.uniform(1, sysbench.opt.tables) +end + +local function get_id() + return sysbench.rand.default(1, sysbench.opt.table_size) +end + +function begin() + stmt.begin:execute() +end + +function commit() + stmt.commit:execute() +end + +function execute_point_selects() + local tnum = get_table_num() + local i + + for i = 1, sysbench.opt.point_selects do + param[tnum].point_selects[1]:set(get_id()) + + stmt[tnum].point_selects:execute() + end +end + +local function execute_range(key) + local tnum = get_table_num() + + for i = 1, sysbench.opt[key] do + local id = get_id() + + param[tnum][key][1]:set(id) + param[tnum][key][2]:set(id + sysbench.opt.range_size - 1) + + stmt[tnum][key]:execute() + end +end + +function execute_simple_ranges() + execute_range("simple_ranges") +end + +function execute_sum_ranges() + execute_range("sum_ranges") +end + +function execute_order_ranges() + execute_range("order_ranges") +end + +function execute_distinct_ranges() + execute_range("distinct_ranges") +end + +function execute_index_updates() + local tnum = get_table_num() + + for i = 1, sysbench.opt.index_updates do + param[tnum].index_updates[1]:set(get_id()) + + stmt[tnum].index_updates:execute() + end +end + +function execute_non_index_updates() + local tnum = get_table_num() + + for i = 1, sysbench.opt.non_index_updates do + param[tnum].non_index_updates[1]:set_rand_str(c_value_template) + param[tnum].non_index_updates[2]:set(get_id()) + + stmt[tnum].non_index_updates:execute() + end +end + +function execute_delete_inserts() + local tnum = get_table_num() + + for i = 1, sysbench.opt.delete_inserts do + local id = get_id() + local k = get_id() + + param[tnum].deletes[1]:set(id) + + param[tnum].inserts[1]:set(id) + param[tnum].inserts[2]:set(k) + param[tnum].inserts[3]:set_rand_str(c_value_template) + param[tnum].inserts[4]:set_rand_str(pad_value_template) + + stmt[tnum].deletes:execute() + stmt[tnum].inserts:execute() + end +end + +-- Re-prepare statements if we have reconnected, which is possible when some of +-- the listed error codes are in the --mysql-ignore-errors list +function sysbench.hooks.before_restart_event(errdesc) + if errdesc.sql_errno == 2013 or -- CR_SERVER_LOST + errdesc.sql_errno == 2055 or -- CR_SERVER_LOST_EXTENDED + errdesc.sql_errno == 2006 or -- CR_SERVER_GONE_ERROR + errdesc.sql_errno == 2011 -- CR_TCP_CONNECTION + then + close_statements() + prepare_statements() + end +end diff --git a/sysbench/oltp_delete.lua b/sysbench/oltp_delete.lua new file mode 100755 index 00000000..23668b2c --- /dev/null +++ b/sysbench/oltp_delete.lua @@ -0,0 +1,34 @@ +#!/usr/bin/sysbench +-- Copyright (C) 2006-2017 Alexey Kopytov + +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; either version 2 of the License, or +-- (at your option) any later version. + +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. + +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +-- ---------------------------------------------------------------------- +-- Delete-Only OLTP benchmark +-- ---------------------------------------------------------------------- + +require("oltp_common") + +function prepare_statements() + prepare_for_each_table("deletes") +end + +function event() + local tnum = sysbench.rand.uniform(1, sysbench.opt.tables) + local id = sysbench.rand.default(1, sysbench.opt.table_size) + + param[tnum].deletes[1]:set(id) + stmt[tnum].deletes:execute() +end diff --git a/sysbench/oltp_insert.lua b/sysbench/oltp_insert.lua new file mode 100755 index 00000000..af8bd1f6 --- /dev/null +++ b/sysbench/oltp_insert.lua @@ -0,0 +1,65 @@ +#!/usr/bin/sysbench +-- Copyright (C) 2006-2017 Alexey Kopytov + +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; either version 2 of the License, or +-- (at your option) any later version. + +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. + +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +-- ---------------------------------------------------------------------- +-- Insert-Only OLTP benchmark +-- ---------------------------------------------------------------------- + +require(".oltp_common") + +sysbench.cmdline.commands.prepare = { + function () + if (not sysbench.opt.auto_inc) then + -- Create empty tables on prepare when --auto-inc is off, since IDs + -- generated on prepare may collide later with values generated by + -- sysbench.rand.unique() + sysbench.opt.table_size=0 + end + + cmd_prepare() + end, + sysbench.cmdline.PARALLEL_COMMAND +} + +function prepare_statements() + -- We do not use prepared statements here, but oltp_common.sh expects this + -- function to be defined +end + +function event() + local table_name = "sbtest" .. sysbench.rand.uniform(1, sysbench.opt.tables) + local k_val = sysbench.rand.default(1, sysbench.opt.table_size) + local c_val = get_c_value() + local pad_val = get_pad_value() + + if (drv:name() == "pgsql" and sysbench.opt.auto_inc) then + con:query(string.format("INSERT INTO %s (k, c, pad) VALUES " .. + "(%d, '%s', '%s')", + table_name, k_val, c_val, pad_val)) + else + if (sysbench.opt.auto_inc) then + i = 0 + else + -- Convert a uint32_t value to SQL INT + i = sysbench.rand.unique() - 2147483648 + end + + con:query(string.format("INSERT INTO %s (id, k, c, pad) VALUES " .. + "(%d, %d, '%s', '%s')", + table_name, i, k_val, c_val, pad_val)) + end +end diff --git a/sysbench/oltp_point_select.lua b/sysbench/oltp_point_select.lua new file mode 100755 index 00000000..b82cb071 --- /dev/null +++ b/sysbench/oltp_point_select.lua @@ -0,0 +1,34 @@ +#!/usr/bin/sysbench +-- Copyright (C) 2006-2017 Alexey Kopytov + +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; either version 2 of the License, or +-- (at your option) any later version. + +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. + +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +-- ---------------------------------------------------------------------- +-- OLTP Point Select benchmark +-- ---------------------------------------------------------------------- + +require("oltp_common") + +function prepare_statements() + -- use 1 query per event, rather than sysbench.opt.point_selects which + -- defaults to 10 in other OLTP scripts + sysbench.opt.point_selects=1 + + prepare_point_selects() +end + +function event() + execute_point_selects() +end diff --git a/sysbench/oltp_read_only.lua b/sysbench/oltp_read_only.lua new file mode 100755 index 00000000..1c9ab05a --- /dev/null +++ b/sysbench/oltp_read_only.lua @@ -0,0 +1,57 @@ +#!/usr/bin/sysbench +-- Copyright (C) 2006-2017 Alexey Kopytov + +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; either version 2 of the License, or +-- (at your option) any later version. + +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. + +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +-- ---------------------------------------------------------------------- +-- Read-Only OLTP benchmark +-- ---------------------------------------------------------------------- + +require("oltp_common") + +function prepare_statements() + prepare_point_selects() + + if not sysbench.opt.skip_trx then + prepare_begin() + prepare_commit() + end + + if sysbench.opt.range_selects then + prepare_simple_ranges() + prepare_sum_ranges() + prepare_order_ranges() + prepare_distinct_ranges() + end +end + +function event() + if not sysbench.opt.skip_trx then + begin() + end + + execute_point_selects() + + if sysbench.opt.range_selects then + execute_simple_ranges() + execute_sum_ranges() + execute_order_ranges() + execute_distinct_ranges() + end + + if not sysbench.opt.skip_trx then + commit() + end +end diff --git a/sysbench/oltp_read_write.lua b/sysbench/oltp_read_write.lua new file mode 100755 index 00000000..b3ec02e0 --- /dev/null +++ b/sysbench/oltp_read_write.lua @@ -0,0 +1,65 @@ +#!/usr/bin/sysbench +-- Copyright (C) 2006-2017 Alexey Kopytov + +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; either version 2 of the License, or +-- (at your option) any later version. + +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. + +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +-- ---------------------------------------------------------------------- +-- Read/Write OLTP benchmark +-- ---------------------------------------------------------------------- + +require("oltp_common") + +function prepare_statements() + if not sysbench.opt.skip_trx then + prepare_begin() + prepare_commit() + end + + prepare_point_selects() + + if sysbench.opt.range_selects then + prepare_simple_ranges() + prepare_sum_ranges() + prepare_order_ranges() + prepare_distinct_ranges() + end + + prepare_index_updates() + prepare_non_index_updates() + prepare_delete_inserts() +end + +function event() + if not sysbench.opt.skip_trx then + begin() + end + + execute_point_selects() + + if sysbench.opt.range_selects then + execute_simple_ranges() + execute_sum_ranges() + execute_order_ranges() + execute_distinct_ranges() + end + + execute_index_updates() + execute_non_index_updates() + execute_delete_inserts() + + if not sysbench.opt.skip_trx then + commit() + end +end diff --git a/sysbench/oltp_update_index.lua b/sysbench/oltp_update_index.lua new file mode 100755 index 00000000..39ae347a --- /dev/null +++ b/sysbench/oltp_update_index.lua @@ -0,0 +1,30 @@ +#!/usr/bin/sysbench +-- Copyright (C) 2006-2017 Alexey Kopytov + +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; either version 2 of the License, or +-- (at your option) any later version. + +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. + +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +-- ---------------------------------------------------------------------- +-- Update-Index OLTP benchmark +-- ---------------------------------------------------------------------- + +require("oltp_common") + +function prepare_statements() + prepare_index_updates() +end + +function event() + execute_index_updates(con) +end diff --git a/sysbench/oltp_update_non_index.lua b/sysbench/oltp_update_non_index.lua new file mode 100755 index 00000000..a504de57 --- /dev/null +++ b/sysbench/oltp_update_non_index.lua @@ -0,0 +1,30 @@ +#!/usr/bin/sysbench +-- Copyright (C) 2006-2017 Alexey Kopytov + +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; either version 2 of the License, or +-- (at your option) any later version. + +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. + +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +-- ---------------------------------------------------------------------- +-- Update-Non-Index OLTP benchmark +-- ---------------------------------------------------------------------- + +require("oltp_common") + +function prepare_statements() + prepare_non_index_updates() +end + +function event() + execute_non_index_updates() +end diff --git a/sysbench/oltp_write_only.lua b/sysbench/oltp_write_only.lua new file mode 100755 index 00000000..1bf814f3 --- /dev/null +++ b/sysbench/oltp_write_only.lua @@ -0,0 +1,47 @@ +#!/usr/bin/sysbench +-- Copyright (C) 2006-2017 Alexey Kopytov + +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; either version 2 of the License, or +-- (at your option) any later version. + +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. + +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +-- ---------------------------------------------------------------------- +-- Write-Only OLTP benchmark +-- ---------------------------------------------------------------------- + +require("oltp_common") + +function prepare_statements() + if not sysbench.opt.skip_trx then + prepare_begin() + prepare_commit() + end + + prepare_index_updates() + prepare_non_index_updates() + prepare_delete_inserts() +end + +function event() + if not sysbench.opt.skip_trx then + begin() + end + + execute_index_updates() + execute_non_index_updates() + execute_delete_inserts() + + if not sysbench.opt.skip_trx then + commit() + end +end diff --git a/sysbench/select_random_points.lua b/sysbench/select_random_points.lua new file mode 100755 index 00000000..386a62a4 --- /dev/null +++ b/sysbench/select_random_points.lua @@ -0,0 +1,72 @@ +#!/usr/bin/sysbench +-- This test is designed for testing MariaDB's key_cache_segments for MyISAM, +-- and should work with other storage engines as well. +-- +-- For details about key_cache_segments please refer to: +-- http://kb.askmonty.org/v/segmented-key-cache +-- + +require("oltp_common") + +-- Add random_points to the list of standard OLTP options +sysbench.cmdline.options.random_points = + {"Number of random points in the IN() clause in generated SELECTs", 10} + +-- Override standard prepare/cleanup OLTP functions, as this benchmark does not +-- support multiple tables +oltp_prepare = prepare +oltp_cleanup = cleanup + +function prepare() + assert(sysbench.opt.tables == 1, "this benchmark does not support " .. + "--tables > 1") + oltp_prepare() +end + +function cleanup() + assert(sysbench.opt.tables == 1, "this benchmark does not support " .. + "--tables > 1") + oltp_cleanup() +end + +function thread_init() + drv = sysbench.sql.driver() + con = drv:connect() + + local points = string.rep("?, ", sysbench.opt.random_points - 1) .. "?" + + stmt = con:prepare(string.format([[ + SELECT id, k, c, pad + FROM sbtest1 + WHERE k IN (%s) + ]], points)) + + params = {} + for j = 1, sysbench.opt.random_points do + params[j] = stmt:bind_create(sysbench.sql.type.INT) + end + + stmt:bind_param(unpack(params)) + + rlen = sysbench.opt.table_size / sysbench.opt.threads + + thread_id = sysbench.tid % sysbench.opt.threads +end + +function thread_done() + stmt:close() + con:disconnect() +end + +function event() + -- To prevent overlapping of our range queries we need to partition the whole + -- table into 'threads' segments and then make each thread work with its + -- own segment. + for i = 1, sysbench.opt.random_points do + local rmin = rlen * thread_id + local rmax = rmin + rlen + params[i]:set(sb_rand(rmin, rmax)) + end + + stmt:execute() +end diff --git a/sysbench/select_random_ranges.lua b/sysbench/select_random_ranges.lua new file mode 100755 index 00000000..f74c1410 --- /dev/null +++ b/sysbench/select_random_ranges.lua @@ -0,0 +1,77 @@ +#!/usr/bin/sysbench +-- This test is designed for testing MariaDB's key_cache_segments for MyISAM, +-- and should work with other storage engines as well. +-- +-- For details about key_cache_segments please refer to: +-- http://kb.askmonty.org/v/segmented-key-cache +-- + +require("oltp_common") + +-- Add --number-of-ranges and --delta to the list of standard OLTP options +sysbench.cmdline.options.number_of_ranges = + {"Number of random BETWEEN ranges per SELECT", 10} +sysbench.cmdline.options.delta = + {"Size of BETWEEN ranges", 5} + +-- Override standard prepare/cleanup OLTP functions, as this benchmark does not +-- support multiple tables +oltp_prepare = prepare +oltp_cleanup = cleanup + +function prepare() + assert(sysbench.opt.tables == 1, "this benchmark does not support " .. + "--tables > 1") + oltp_prepare() +end + +function cleanup() + assert(sysbench.opt.tables == 1, "this benchmark does not support " .. + "--tables > 1") + oltp_cleanup() +end + +function thread_init() + drv = sysbench.sql.driver() + con = drv:connect() + + local ranges = string.rep("k BETWEEN ? AND ? OR ", + sysbench.opt.number_of_ranges - 1) .. + "k BETWEEN ? AND ?" + + stmt = con:prepare(string.format([[ + SELECT count(k) + FROM sbtest1 + WHERE %s]], ranges)) + + params = {} + for j = 1, sysbench.opt.number_of_ranges*2 do + params[j] = stmt:bind_create(sysbench.sql.type.INT) + end + + stmt:bind_param(unpack(params)) + + rlen = sysbench.opt.table_size / sysbench.opt.threads + + thread_id = sysbench.tid % sysbench.opt.threads +end + +function thread_done() + stmt:close() + con:disconnect() +end + +function event() + -- To prevent overlapping of our range queries we need to partition the whole + -- table into 'threads' segments and then make each thread work with its + -- own segment. + for i = 1, sysbench.opt.number_of_ranges*2, 2 do + local rmin = rlen * thread_id + local rmax = rmin + rlen + local val = sb_rand(rmin, rmax) + params[i]:set(val) + params[i+1]:set(val + sysbench.opt.delta) + end + + stmt:execute() +end