mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-08-29 21:18:02 +00:00
[3736] Removed dhcp-ubench and folders.
This commit is contained in:
parent
bfce8a989b
commit
a25ec56db7
@ -2,7 +2,7 @@ ACLOCAL_AMFLAGS = -I m4macros ${ACLOCAL_FLAGS}
|
||||
# ^^^^^^^^ This has to be the first line and cannot come later in this
|
||||
# Makefile.am due to some bork in some versions of autotools.
|
||||
|
||||
SUBDIRS = compatcheck doc . ext src tests m4macros
|
||||
SUBDIRS = compatcheck doc . ext src m4macros
|
||||
USE_LCOV=@USE_LCOV@
|
||||
LCOV=@LCOV@
|
||||
GENHTML=@GENHTML@
|
||||
@ -81,7 +81,6 @@ endif
|
||||
if HAVE_OPENSSL
|
||||
openssl/\* \
|
||||
endif
|
||||
tests/\* \
|
||||
unittests/\* \
|
||||
\*_unittests.cc \
|
||||
\*_unittest.cc \
|
||||
|
@ -1504,8 +1504,6 @@ AC_CONFIG_FILES([compatcheck/Makefile
|
||||
src/lib/util/threads/tests/Makefile
|
||||
src/lib/util/unittests/Makefile
|
||||
tools/path_replacer.sh
|
||||
tests/Makefile
|
||||
tests/tools/Makefile
|
||||
])
|
||||
|
||||
AC_CONFIG_COMMANDS([permissions], [
|
||||
|
@ -1 +0,0 @@
|
||||
SUBDIRS = tools
|
@ -1 +0,0 @@
|
||||
SUBDIRS = .
|
@ -1,65 +0,0 @@
|
||||
# Linux switches
|
||||
CFLAGS= -Ofast -Wall -pedantic -Wextra
|
||||
|
||||
# Mac OS: We don't use pedantic as Mac OS version of MySQL (5.5.24) does use long long (not part of ISO C++)
|
||||
#CFLAGS=-g -O0 -Wall -Wextra -I/opt/local/include
|
||||
|
||||
# Mac OS does not require -lrt
|
||||
# Linux requires -lrt
|
||||
LDFLAGS=-lrt
|
||||
|
||||
MEMFILE_CFLAGS=
|
||||
MEMFILE_LDFLAGS=
|
||||
|
||||
# It is mysql_config on most Linux systems and mysql_config5 on Mac OS
|
||||
MYSQL_CONFIG=mysql_config
|
||||
|
||||
MYSQL_CFLAGS=`$(MYSQL_CONFIG) --cflags`
|
||||
MYSQL_LDFLAGS=`$(MYSQL_CONFIG) --libs`
|
||||
|
||||
SQLITE_CFLAGS=`pkg-config sqlite3 --cflags`
|
||||
SQLITE_LDFLAGS=`pkg-config sqlite3 --libs`
|
||||
|
||||
all: mysql_ubench sqlite_ubench memfile_ubench
|
||||
|
||||
doc: dhcp-perf-guide.html dhcp-perf-guide.pdf
|
||||
|
||||
mysql_ubench.o: mysql_ubench.cc mysql_ubench.h benchmark.h
|
||||
$(CXX) $< -c $(CFLAGS) $(MYSQL_CFLAGS)
|
||||
|
||||
benchmark.o: benchmark.cc benchmark.h
|
||||
$(CXX) $< -c $(CFLAGS) $(MYSQL_CFLAGS)
|
||||
|
||||
mysql_ubench: mysql_ubench.o benchmark.o
|
||||
$(CXX) $< benchmark.o -o mysql_ubench $(CFLAGS) $(MYSQL_CFLAGS) $(LDFLAGS) $(MYSQL_LDFLAGS)
|
||||
|
||||
sqlite_ubench.o: sqlite_ubench.cc sqlite_ubench.h benchmark.h
|
||||
$(CXX) $< -c $(CFLAGS) $(SQLLITE_CFLAGS)
|
||||
|
||||
sqlite_ubench: sqlite_ubench.o benchmark.o
|
||||
$(CXX) $< benchmark.o -o sqlite_ubench $(CFLAGS) $(SQLITE_CFLAGS) $(LDFLAGS) $(SQLITE_LDFLAGS)
|
||||
|
||||
memfile_ubench.o: memfile_ubench.cc memfile_ubench.h benchmark.h
|
||||
$(CXX) $< -c $(CFLAGS) $(MEMFILE_CFLAGS)
|
||||
|
||||
memfile_ubench: memfile_ubench.o benchmark.o
|
||||
$(CXX) $< benchmark.o -o memfile_ubench $(LDFLAGS) $(MEMFILE_LDFLAGS)
|
||||
|
||||
clean:
|
||||
rm -f mysql_ubench sqlite_ubench memfile_ubench *.o
|
||||
|
||||
version.ent:
|
||||
ln -s ../../../doc/version.ent
|
||||
|
||||
dhcp-perf-guide.html: dhcp-perf-guide.xml version.ent
|
||||
xsltproc --novalid --xinclude --nonet \
|
||||
-o $@ \
|
||||
--path ../../../doc \
|
||||
--stringparam section.autolabel 1 \
|
||||
--stringparam section.label.includes.component.label 1 \
|
||||
--stringparam html.stylesheet bind10-guide.css \
|
||||
http://docbook.sourceforge.net/release/xsl/current/html/docbook.xsl \
|
||||
dhcp-perf-guide.xml
|
||||
|
||||
dhcp-perf-guide.pdf: dhcp-perf-guide.xml
|
||||
dblatex -P doc.collab.show=0 -P latex.output.revhistory=0 $<
|
@ -1,10 +0,0 @@
|
||||
|
||||
This directory contains benchmarks for various planned and considered database
|
||||
backends for BIND10 DHCP, codename Kea.
|
||||
|
||||
Before using the code, please read DHCP Performance Guide, available in
|
||||
HTML and PDF formats.
|
||||
|
||||
To compile the code, type: make
|
||||
|
||||
To regenerate documentation, type: make doc
|
@ -1,198 +0,0 @@
|
||||
// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
#include <iostream>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include "benchmark.h"
|
||||
|
||||
// The following headers are for getting precise time (clock_gettime on Linux or that mac os thingie)
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#ifdef __MACH__
|
||||
#include <mach/clock.h>
|
||||
#include <mach/mach.h>
|
||||
#endif
|
||||
|
||||
|
||||
using namespace std;
|
||||
|
||||
uBenchmark::uBenchmark(uint32_t iterations, const std::string& dbname,
|
||||
bool sync /*= false*/, bool verbose /*= true*/,
|
||||
const std::string& host /* = "" */,
|
||||
const std::string& user /* = "" */,
|
||||
const std::string& pass /* = "" */)
|
||||
:num_(iterations), sync_(sync), verbose_(verbose),
|
||||
hostname_(host), user_(user), passwd_(pass), dbname_(dbname),
|
||||
hitratio_(0.9f), compiled_stmt_(true)
|
||||
{
|
||||
/// @todo: make compiled statements a configurable parameter
|
||||
|
||||
/// @todo: convert hitratio_ to user-configurable parameter
|
||||
|
||||
memset(ts_, 0, sizeof(ts_));
|
||||
}
|
||||
|
||||
void uBenchmark::usage() {
|
||||
cout << "This is a benchmark designed to measure expected performance" << endl;
|
||||
cout << "of several backends. This backend identifies itself as:" << endl;
|
||||
printInfo();
|
||||
|
||||
cout << endl << "Possible command-line parameters:" << endl;
|
||||
cout << " -h - help (you are reading this)" << endl;
|
||||
cout << " -m hostname - specifies MySQL server to connect (MySQL backend only)" << endl;
|
||||
cout << " -u username - specifies MySQL user name (MySQL backend only)" << endl;
|
||||
cout << " -p password - specifies MySQL passwod (MySQL backend only)" << endl;
|
||||
cout << " -f name - database or filename (MySQL, SQLite and memfile)" << endl;
|
||||
cout << " -n integer - number of test iterations (MySQL, SQLite and memfile)" << endl;
|
||||
cout << " -s yes|no - synchronous/asynchronous operation (MySQL, SQLite and memfile)" << endl;
|
||||
cout << " -v yes|no - verbose mode (MySQL, SQLite and memfile)" << endl;
|
||||
cout << " -c yes|no - compiled statements (MySQL and SQLite)" << endl;
|
||||
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
void uBenchmark::parseCmdline(int argc, char* const argv[]) {
|
||||
int ch;
|
||||
|
||||
while ((ch = getopt(argc, argv, "hm:u:p:f:n:s:v:c:")) != -1) {
|
||||
switch (ch) {
|
||||
case 'h':
|
||||
usage();
|
||||
case 'm':
|
||||
hostname_ = string(optarg);
|
||||
break;
|
||||
case 'u':
|
||||
user_ = string(optarg);
|
||||
break;
|
||||
case 'p':
|
||||
passwd_ = string(optarg);
|
||||
break;
|
||||
case 'f':
|
||||
dbname_ = string(optarg);
|
||||
break;
|
||||
case 'n':
|
||||
try {
|
||||
num_ = boost::lexical_cast<unsigned int>(optarg);
|
||||
} catch (const boost::bad_lexical_cast &) {
|
||||
cerr << "Failed to parse number of iterations (-n option):"
|
||||
<< optarg << endl;
|
||||
usage();
|
||||
}
|
||||
break;
|
||||
case 'c':
|
||||
compiled_stmt_ = !strcasecmp(optarg, "yes") || !strcmp(optarg, "1");
|
||||
break;
|
||||
case 's':
|
||||
sync_ = !strcasecmp(optarg, "yes") || !strcmp(optarg, "1");
|
||||
break;
|
||||
case 'v':
|
||||
verbose_ = !strcasecmp(optarg, "yes") || !strcmp(optarg, "1");
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void uBenchmark::failure(const char* operation) {
|
||||
cout << "Error during " << operation << endl;
|
||||
throw string(operation);
|
||||
}
|
||||
|
||||
void uBenchmark::printClock(const std::string& operation, uint32_t num,
|
||||
const struct timespec& before,
|
||||
const struct timespec& after) {
|
||||
long int tv_sec = after.tv_sec - before.tv_sec;
|
||||
|
||||
long int tv_nsec = after.tv_nsec - before.tv_nsec;
|
||||
|
||||
if (tv_nsec < 0) {
|
||||
tv_sec--;
|
||||
tv_nsec += 1000000000; // 10^9
|
||||
}
|
||||
|
||||
double oneoper = (tv_nsec/1000 + tv_sec*1000000)/num;
|
||||
|
||||
cout << operation << " repeated " << num << " times took "
|
||||
<< tv_sec << " s, " << tv_nsec/1000 << " us, 1 operation took "
|
||||
<< oneoper << "us (or " << (1000000/oneoper) << " oper/sec)" << endl;
|
||||
|
||||
}
|
||||
|
||||
int uBenchmark::run() {
|
||||
|
||||
cout << "Starting test. Parameters:" << endl
|
||||
<< "Number of iterations : " << num_ << endl
|
||||
<< "Sync/async : " << (sync_ ? "sync" : "async") << endl
|
||||
<< "Verbose : " << (verbose_ ? "verbose" : "quiet") << endl
|
||||
<< "Compiled statements : " << (compiled_stmt_ ? "yes": "no") << endl
|
||||
<< "Database name : " << dbname_ << endl
|
||||
<< "MySQL hostname : " << hostname_ << endl
|
||||
<< "MySQL username : " << user_ << endl
|
||||
<< "MySQL password : " << passwd_ << endl << endl;
|
||||
|
||||
|
||||
srandom(time(NULL));
|
||||
|
||||
try {
|
||||
connect();
|
||||
|
||||
ts_[0] = getTime();
|
||||
|
||||
createLease4Test();
|
||||
ts_[1] = getTime();
|
||||
|
||||
searchLease4Test();
|
||||
ts_[2] = getTime();
|
||||
|
||||
updateLease4Test();
|
||||
ts_[3] = getTime();
|
||||
|
||||
deleteLease4Test();
|
||||
ts_[4] = getTime();
|
||||
|
||||
disconnect();
|
||||
|
||||
} catch (const std::string& e) {
|
||||
cout << "Failed: " << e << endl;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
printClock("Create leases4", num_, ts_[0], ts_[1]);
|
||||
printClock("Search leases4", num_, ts_[1], ts_[2]);
|
||||
printClock("Update leases4", num_, ts_[2], ts_[3]);
|
||||
printClock("Delete leases4", num_, ts_[3], ts_[4]);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
struct timespec uBenchmark::getTime() {
|
||||
struct timespec ts;
|
||||
|
||||
#ifdef __MACH__ // OS X does not have clock_gettime, use clock_get_time
|
||||
clock_serv_t cclock;
|
||||
mach_timespec_t mts;
|
||||
host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
|
||||
clock_get_time(cclock, &mts);
|
||||
mach_port_deallocate(mach_task_self(), cclock);
|
||||
ts.tv_sec = mts.tv_sec;
|
||||
ts.tv_nsec = mts.tv_nsec;
|
||||
#else
|
||||
clock_gettime(CLOCK_REALTIME, &ts);
|
||||
#endif
|
||||
|
||||
return ts;
|
||||
}
|
@ -1,209 +0,0 @@
|
||||
// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
#include <string>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef BENCHMARK_H
|
||||
#define BENCHMARK_H
|
||||
|
||||
/// @brief Micro-benchmark base class.
|
||||
///
|
||||
/// This class represents an abstract DHCP database backend benchmark.
|
||||
/// It is not intended to be used directly, but serves as a common
|
||||
/// denominator for specific backend benchmarks that are derived from
|
||||
/// it. Currently there are at least 3 benchmarks implemented that
|
||||
/// take advantage of it:
|
||||
/// - MySQL (MySQL_uBenchmark)
|
||||
/// - SQLite (SQLite_uBenchmark)
|
||||
/// - memfile (memfile_uBenchmark)
|
||||
class uBenchmark {
|
||||
public:
|
||||
|
||||
/// @brief the sole constructor, used by all derivated benchmarks
|
||||
///
|
||||
/// @param iterations number of iterations of each step (insert, search,
|
||||
/// update, delete)
|
||||
/// @param dbname name of the database (that is backend-specific, either
|
||||
/// filename or DB name)
|
||||
/// @param sync sync or async test mode
|
||||
/// @param verbose should extra logging be enabled?
|
||||
/// @param host some backends (currently only MySQL) need this (optional)
|
||||
/// @param username some backends (currently only MySQL) need this (optional)
|
||||
/// @param pass some backends (currently only MySQL) need this (optional)
|
||||
uBenchmark(uint32_t iterations, const std::string& dbname,
|
||||
bool sync, bool verbose,
|
||||
const std::string& host = "",
|
||||
const std::string& username = "",
|
||||
const std::string& pass = "");
|
||||
|
||||
/// @brief Prints version information about specific backend.
|
||||
///
|
||||
/// The implementation is provided by the DB-specific class.
|
||||
virtual void printInfo() = 0;
|
||||
|
||||
/// @brief Opens a connection to the database.
|
||||
///
|
||||
/// The implementation is provided by the DB-specific class.
|
||||
virtual void connect() = 0;
|
||||
|
||||
/// @brief Closes connection to the database.
|
||||
///
|
||||
/// The implementation is provided by the DB-specific class.
|
||||
virtual void disconnect() = 0;
|
||||
|
||||
/// @brief Benchmarks IPv4 address lease creation.
|
||||
///
|
||||
/// That benchmark method will be called first.
|
||||
/// It is expected to create specific number of leases,
|
||||
/// as specified by \ref num_ parameter. Following
|
||||
/// methods (searchLease4Test(), updateLease4Test(),
|
||||
/// and deleteLease4Test()) assume that lease creation
|
||||
/// is successful. The benchmark is expected to create leases
|
||||
/// starting from BASE_ADDR4 and ending on BASE_ADDR4 + num_.
|
||||
///
|
||||
/// The implementation is provided by the DB-specific class.
|
||||
virtual void createLease4Test() = 0;
|
||||
|
||||
/// @brief Benchmarks IPv4 address lease search.
|
||||
///
|
||||
/// This is the second benchmark in a series of four.
|
||||
/// It is called after createLease4Test(), so it expects that the
|
||||
/// database is populated with at least \ref num_ leases.
|
||||
/// It repeats search for a lease num_ times.
|
||||
///
|
||||
/// The algorithm randomly picks a lease with \ref hitratio_ (typically 90%)
|
||||
/// chance of finding a lease. During typical DHCP operation the server
|
||||
/// sometimes wants to check if specific lease is assigned or not and the
|
||||
/// lease is sometimes not present (e.g. when randomly trying to pick a new
|
||||
/// lease for a new client or doing confirm). Although rather unlikely,
|
||||
/// cases when searching for non-existing leases may be more costly,
|
||||
/// thus should be modelled.
|
||||
///
|
||||
/// The implementation is provided by the DB-specific class.
|
||||
virtual void searchLease4Test() = 0;
|
||||
|
||||
/// @brief Benchmarks IPv4 address lease update.
|
||||
///
|
||||
/// This is the third benchmark in a series of four.
|
||||
/// It is called after createLease4Test(), so it expects that the
|
||||
/// database is populated with at least \ref num_ leases.
|
||||
///
|
||||
/// In a normal DHCP operation, search and update operations are used
|
||||
/// together, but for the benchmarking purposes they are executed
|
||||
/// separately here. Once a lease is found, it is being updated. Typically
|
||||
/// the update is just changing lease expiration timers, so that is what
|
||||
/// the test does. It exploits the fact that there are num_ leases
|
||||
/// in the database, so it picks randomly an address from
|
||||
/// BASE_ADDR4 ... BASE_ADDR4 + num_ range and has a guarantee for the lease
|
||||
/// to be present.
|
||||
///
|
||||
/// The implementation is provided by the DB-specific class.
|
||||
virtual void updateLease4Test() = 0;
|
||||
|
||||
/// @brief Benchmarks IPv4 address lease removal.
|
||||
///
|
||||
/// This is the last benchmark in a series of four.
|
||||
/// It is called after createLease4Test(), so it expects that the
|
||||
/// database is populated with at least \ref num_ leases.
|
||||
///
|
||||
/// It is expected to iteratively delete all num_ leases from
|
||||
/// the database.
|
||||
///
|
||||
/// The implementation is provided by the DB-specific class.
|
||||
virtual void deleteLease4Test() = 0;
|
||||
|
||||
/// @brief Utility function for reporting errors.
|
||||
///
|
||||
/// Benchmarks should call that function when something goes wrong.
|
||||
/// details of the problem must be passed as a parameter. As the benchmark
|
||||
/// is not designed to recover from errors, reporting an error aborts
|
||||
/// benchmark execution.
|
||||
///
|
||||
/// @param operation description of the operation that caused failure
|
||||
virtual void failure(const char* operation);
|
||||
|
||||
/// @brief Prints elapsed time of a specific operation
|
||||
///
|
||||
/// This method prints out elapsed time of a specific benchmark, together
|
||||
/// with additional statistics.
|
||||
///
|
||||
/// @param operation name of the operation (usually create, search, update, delete)
|
||||
/// @param num number or iterations (used for statistics)
|
||||
/// @param before timestamp before execution
|
||||
/// @param after timestamp after execution
|
||||
void printClock(const std::string& operation, uint32_t num,
|
||||
const struct timespec& before,
|
||||
const struct timespec& after);
|
||||
|
||||
/// @brief Main benchmark execution routine
|
||||
///
|
||||
/// This method calls create, search, update and delete benchmarks
|
||||
/// and measures appropriate timestamps in ts_ table.
|
||||
///
|
||||
/// @return 0 if the run was successful, negative value if detected errors
|
||||
int run();
|
||||
|
||||
/// @brief parses command-line parameters
|
||||
///
|
||||
/// This method parses command-line parameters and sets up appropriate
|
||||
/// values. It is ok to pass argc, argv from main() here.
|
||||
///
|
||||
/// This method may not return if -h (help) was specified or invalid
|
||||
/// arguments are passed. Appropriate error and help will be displayed
|
||||
/// and the program will terminate.
|
||||
///
|
||||
/// @param argc number of arguments
|
||||
/// @param argv array to the arguments
|
||||
void parseCmdline(int argc, char* const argv[]);
|
||||
|
||||
protected:
|
||||
/// @brief prints out command-line help (list of parameters + version)
|
||||
void usage();
|
||||
|
||||
/// @brief a wrapper around OS-specific method for getting time
|
||||
struct timespec getTime();
|
||||
|
||||
/// Number of operations (e.g. insert lease num times)
|
||||
uint32_t num_;
|
||||
|
||||
/// Synchronous or asynchronous mode?
|
||||
bool sync_;
|
||||
|
||||
/// Should the test print out extra information?
|
||||
bool verbose_;
|
||||
|
||||
// DB parameters
|
||||
std::string hostname_; // used by MySQL only
|
||||
std::string user_; // used by MySQL only
|
||||
std::string passwd_; // used by MySQL only
|
||||
std::string dbname_; // used by MySQL, SQLite and memfile
|
||||
|
||||
/// @brief hit ratio for search test (must be between 0.0 and 1.0)
|
||||
///
|
||||
/// This parameter is used in search benchmark. The formula causes the
|
||||
/// search to find something a lease in 90% cases of hit ratio is 0.9.
|
||||
float hitratio_;
|
||||
|
||||
/// benchmarks must generate the leases starting from 1.0.0.0 address
|
||||
const static uint32_t BASE_ADDR4 = 0x01000000;
|
||||
|
||||
/// five timestamps (1 at the beginning and 4 after each step)
|
||||
struct timespec ts_[5];
|
||||
|
||||
/// should compiled statements be used?
|
||||
bool compiled_stmt_;
|
||||
};
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
@ -1,356 +0,0 @@
|
||||
// Copyright (C) 2012, 2015 Internet Systems Consortium, Inc. ("ISC")
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include "memfile_ubench.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
/// @brief In-memory + lease file database implementation
|
||||
///
|
||||
/// This is a simplified in-memory database that mimics ISC DHCP4 implementation.
|
||||
/// It uses STL and boost: std::map for storage, boost::shared ptr for memory
|
||||
/// management. It does use C file operations (fopen, fwrite, etc.), because
|
||||
/// C++ streams does not offer any easy way to flush their contents, like
|
||||
/// fflush() and fsync() does.
|
||||
///
|
||||
/// IPv4 address is used as a key in the hash.
|
||||
class memfile_LeaseMgr {
|
||||
public:
|
||||
|
||||
/// A hash table for Lease4 leases.
|
||||
typedef std::map<uint32_t /* addr */, Lease4Ptr /* lease info */> IPv4Hash;
|
||||
|
||||
/// An iterator for Lease4 hash table.
|
||||
typedef std::map<uint32_t, Lease4Ptr>::iterator leaseIt;
|
||||
|
||||
/// @brief The sole memfile lease manager constructor
|
||||
///
|
||||
/// @param filename name of the lease file (will be overwritten)
|
||||
/// @param sync should operations be
|
||||
memfile_LeaseMgr(const std::string& filename, bool sync);
|
||||
|
||||
/// @brief Destructor (closes file)
|
||||
~memfile_LeaseMgr();
|
||||
|
||||
/// @brief adds a lease to the hash
|
||||
///
|
||||
/// @param lease lease to be added
|
||||
bool addLease(Lease4Ptr lease);
|
||||
|
||||
/// @brief returns existing lease
|
||||
///
|
||||
/// @param addr address of the searched lease
|
||||
///
|
||||
/// @return smart pointer to the lease (or NULL if lease is not found)
|
||||
Lease4Ptr getLease(uint32_t addr);
|
||||
|
||||
/// @brief Simplified lease update.
|
||||
///
|
||||
/// Searches for a lease and then updates its client last transmission
|
||||
/// time. Writes new lease content to lease file (and calls fflush()/fsync(),
|
||||
/// if synchronous operation is enabled).
|
||||
///
|
||||
/// @param addr IPv4 address
|
||||
/// @param new_cltt New client last transmission time
|
||||
///
|
||||
/// @return pointer to the updated lease (or NULL)
|
||||
Lease4Ptr updateLease(uint32_t addr, uint32_t new_cltt);
|
||||
|
||||
/// @brief Deletes a lease.
|
||||
///
|
||||
/// @param addr IPv4 address of the lease to be deleted.
|
||||
///
|
||||
/// @return true if deletion was successful, false if no such lease exists
|
||||
bool deleteLease(uint32_t addr);
|
||||
|
||||
protected:
|
||||
|
||||
/// @brief Writes updated lease to a file.
|
||||
///
|
||||
/// @param lease lease to be written
|
||||
void writeLease(Lease4Ptr lease);
|
||||
|
||||
/// Name of the lease file.
|
||||
std::string filename_;
|
||||
|
||||
/// should we do flush after each operation?
|
||||
bool sync_;
|
||||
|
||||
/// File handle to the open lease file.
|
||||
FILE * file_;
|
||||
|
||||
/// Hash table for IPv4 leases
|
||||
IPv4Hash ip4Hash_;
|
||||
};
|
||||
|
||||
memfile_LeaseMgr::memfile_LeaseMgr(const std::string& filename, bool sync)
|
||||
: filename_(filename), sync_(sync) {
|
||||
file_ = fopen(filename.c_str(), "w");
|
||||
if (!file_) {
|
||||
throw "Failed to create file " + filename;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
memfile_LeaseMgr::~memfile_LeaseMgr() {
|
||||
fclose(file_);
|
||||
}
|
||||
|
||||
void memfile_LeaseMgr::writeLease(Lease4Ptr lease) {
|
||||
fprintf(file_, "lease %d {\n hw-addr ", lease->addr);
|
||||
for (std::vector<uint8_t>::const_iterator it = lease->hwaddr.begin();
|
||||
it != lease->hwaddr.end(); ++it) {
|
||||
fprintf(file_, "%02x:", *it);
|
||||
}
|
||||
fprintf(file_, ";\n client-id ");
|
||||
for (std::vector<uint8_t>::const_iterator it = lease->client_id.begin();
|
||||
it != lease->client_id.end(); ++it) {
|
||||
fprintf(file_, "%02x:", *it);
|
||||
}
|
||||
fprintf(file_, ";\n valid-lifetime %d;\n recycle-time %d;\n"
|
||||
" cltt %d;\n pool-id %d;\n fixed %s; hostname %s;\n"
|
||||
" fqdn_fwd %s;\n fqdn_rev %s;\n};\n",
|
||||
lease->valid_lft, lease->recycle_time, (int)lease->cltt,
|
||||
lease->pool_id, lease->fixed?"true":"false",
|
||||
lease->hostname.c_str(), lease->fqdn_fwd?"true":"false",
|
||||
lease->fqdn_rev?"true":"false");
|
||||
|
||||
if (sync_) {
|
||||
fflush(file_);
|
||||
fsync(fileno(file_));
|
||||
}
|
||||
}
|
||||
|
||||
bool memfile_LeaseMgr::addLease(Lease4Ptr lease) {
|
||||
if (ip4Hash_.find(lease->addr) != ip4Hash_.end()) {
|
||||
// there is such an address already in the hash
|
||||
return false;
|
||||
}
|
||||
ip4Hash_.insert(pair<uint32_t, Lease4Ptr>(lease->addr, lease));
|
||||
lease->hostname = "add";
|
||||
writeLease(lease);
|
||||
return (true);
|
||||
}
|
||||
|
||||
Lease4Ptr memfile_LeaseMgr::getLease(uint32_t addr) {
|
||||
leaseIt x = ip4Hash_.find(addr);
|
||||
if (x != ip4Hash_.end()) {
|
||||
return x->second; // found
|
||||
}
|
||||
|
||||
// not found
|
||||
return Lease4Ptr();
|
||||
}
|
||||
|
||||
Lease4Ptr memfile_LeaseMgr::updateLease(uint32_t addr, uint32_t new_cltt) {
|
||||
leaseIt x = ip4Hash_.find(addr);
|
||||
if (x != ip4Hash_.end()) {
|
||||
x->second->cltt = new_cltt;
|
||||
x->second->hostname = "update";
|
||||
writeLease(x->second);
|
||||
return x->second;
|
||||
}
|
||||
return Lease4Ptr();
|
||||
}
|
||||
|
||||
bool memfile_LeaseMgr::deleteLease(uint32_t addr) {
|
||||
leaseIt x = ip4Hash_.find(addr);
|
||||
if (x != ip4Hash_.end()) {
|
||||
x->second->hostname = "delete";
|
||||
writeLease(x->second);
|
||||
ip4Hash_.erase(x);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
memfile_uBenchmark::memfile_uBenchmark(const string& filename,
|
||||
uint32_t num_iterations,
|
||||
bool sync,
|
||||
bool verbose)
|
||||
:uBenchmark(num_iterations, filename, sync, verbose) {
|
||||
}
|
||||
|
||||
void memfile_uBenchmark::connect() {
|
||||
try {
|
||||
leaseMgr_ = new memfile_LeaseMgr(dbname_, sync_);
|
||||
} catch (const std::string& e) {
|
||||
failure(e.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void memfile_uBenchmark::disconnect() {
|
||||
delete leaseMgr_;
|
||||
leaseMgr_ = NULL;
|
||||
}
|
||||
|
||||
void memfile_uBenchmark::createLease4Test() {
|
||||
if (!leaseMgr_) {
|
||||
throw "No LeaseMgr instantiated.";
|
||||
}
|
||||
|
||||
uint32_t addr = BASE_ADDR4; // Let's start with 1.0.0.0 address
|
||||
const uint8_t hwaddr_len = 20; // Not a real field
|
||||
char hwaddr_tmp[hwaddr_len];
|
||||
const uint8_t client_id_len = 128;
|
||||
char client_id_tmp[client_id_len];
|
||||
uint32_t valid_lft = 1000; // We can use the same value for all leases
|
||||
uint32_t recycle_time = 0; // Not supported in any foreseeable future,
|
||||
// so keep this as 0
|
||||
time_t cltt = time(NULL); // Timestamp
|
||||
uint32_t pool_id = 0; // Let's use pools 0-99
|
||||
bool fixed = false;
|
||||
string hostname("foo"); // Will generate it dynamically
|
||||
bool fqdn_fwd = true; // Let's pretend to do AAAA update
|
||||
bool fqdn_rev = true; // Let's pretend to do PTR update
|
||||
|
||||
cout << "CREATE: ";
|
||||
|
||||
// While we could put the data directly into vector, I would like to
|
||||
// keep the code as similar to other benchmarks as possible
|
||||
for (uint8_t i = 0; i < hwaddr_len; ++i) {
|
||||
hwaddr_tmp[i] = 'A' + i; // let's make hwaddr consisting of letter
|
||||
}
|
||||
vector<uint8_t> hwaddr(hwaddr_tmp, hwaddr_tmp + hwaddr_len - 1);
|
||||
|
||||
for (uint8_t i = 0; i < client_id_len; i++) {
|
||||
client_id_tmp[i] = 33 + i; // 33 is being the first, non whitespace
|
||||
// printable ASCII character
|
||||
}
|
||||
vector<uint8_t> client_id(client_id_tmp, client_id_tmp + client_id_len - 1);
|
||||
|
||||
for (uint32_t i = 0; i < num_; ++i) {
|
||||
|
||||
cltt++;
|
||||
|
||||
Lease4Ptr lease = boost::shared_ptr<Lease4>(new Lease4());
|
||||
lease->addr = addr;
|
||||
lease->hwaddr = hwaddr;
|
||||
lease->client_id = client_id;
|
||||
lease->valid_lft = valid_lft;
|
||||
lease->recycle_time = recycle_time;
|
||||
lease->cltt = cltt;
|
||||
lease->pool_id = pool_id;
|
||||
lease->fixed = fixed;
|
||||
lease->hostname = hostname;
|
||||
lease->fqdn_fwd = fqdn_fwd;
|
||||
lease->fqdn_rev = fqdn_rev;
|
||||
|
||||
if (!leaseMgr_->addLease(lease)) {
|
||||
failure("addLease() failed");
|
||||
} else {
|
||||
if (verbose_) {
|
||||
cout << ".";
|
||||
}
|
||||
};
|
||||
|
||||
addr++;
|
||||
}
|
||||
cout << endl;
|
||||
}
|
||||
|
||||
void memfile_uBenchmark::searchLease4Test() {
|
||||
if (!leaseMgr_) {
|
||||
throw "No LeaseMgr instantiated.";
|
||||
}
|
||||
|
||||
cout << "RETRIEVE: ";
|
||||
|
||||
for (uint32_t i = 0; i < num_; i++) {
|
||||
uint32_t x = BASE_ADDR4 + random() % int(num_ / hitratio_);
|
||||
|
||||
Lease4Ptr lease = leaseMgr_->getLease(x);
|
||||
if (verbose_) {
|
||||
cout << (lease?".":"X");
|
||||
}
|
||||
}
|
||||
|
||||
cout << endl;
|
||||
}
|
||||
|
||||
void memfile_uBenchmark::updateLease4Test() {
|
||||
if (!leaseMgr_) {
|
||||
throw "No LeaseMgr instantiated.";
|
||||
}
|
||||
|
||||
cout << "UPDATE: ";
|
||||
|
||||
time_t cltt = time(NULL);
|
||||
|
||||
for (uint32_t i = 0; i < num_; i++) {
|
||||
|
||||
uint32_t x = BASE_ADDR4 + random() % num_;
|
||||
|
||||
Lease4Ptr lease = leaseMgr_->updateLease(x, cltt);
|
||||
if (!lease) {
|
||||
stringstream tmp;
|
||||
tmp << "UPDATE failed for lease " << hex << x << dec;
|
||||
failure(tmp.str().c_str());
|
||||
}
|
||||
if (verbose_) {
|
||||
cout << ".";
|
||||
}
|
||||
}
|
||||
|
||||
cout << endl;
|
||||
}
|
||||
|
||||
void memfile_uBenchmark::deleteLease4Test() {
|
||||
if (!leaseMgr_) {
|
||||
throw "No LeaseMgr instantiated.";
|
||||
}
|
||||
|
||||
cout << "DELETE: ";
|
||||
|
||||
for (uint32_t i = 0; i < num_; i++) {
|
||||
|
||||
uint32_t x = BASE_ADDR4 + i;
|
||||
|
||||
if (!leaseMgr_->deleteLease(x)) {
|
||||
stringstream tmp;
|
||||
tmp << "UPDATE failed for lease " << hex << x << dec;
|
||||
failure(tmp.str().c_str());
|
||||
}
|
||||
if (verbose_) {
|
||||
cout << ".";
|
||||
}
|
||||
}
|
||||
|
||||
cout << endl;
|
||||
}
|
||||
|
||||
void memfile_uBenchmark::printInfo() {
|
||||
cout << "Memory db (using std::map) + write-only file." << endl;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char * const argv[]) {
|
||||
|
||||
const char * filename = "dhcpd.leases";
|
||||
uint32_t num = 100;
|
||||
bool sync = true;
|
||||
bool verbose = false;
|
||||
|
||||
memfile_uBenchmark bench(filename, num, sync, verbose);
|
||||
|
||||
bench.parseCmdline(argc, argv);
|
||||
|
||||
int result = bench.run();
|
||||
|
||||
return (result);
|
||||
}
|
@ -1,103 +0,0 @@
|
||||
// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include "benchmark.h"
|
||||
|
||||
/// @brief Structure of the Lease4 that is kept in memory
|
||||
struct Lease4 {
|
||||
uint32_t addr; /// IPv4 address
|
||||
std::vector<uint8_t> hwaddr; /// hardware address
|
||||
std::vector<uint8_t> client_id; /// client-identifier
|
||||
uint32_t valid_lft; /// valid lifetime timestamp
|
||||
uint32_t recycle_time; /// timer for keeping lease after expiration/release
|
||||
/// (currently not used)
|
||||
time_t cltt; /// client last transmission time
|
||||
uint32_t pool_id; /// ID of the pool the lease belongs to
|
||||
bool fixed; /// is this lease fixed?
|
||||
std::string hostname; /// client hostname (may be empty)
|
||||
bool fqdn_fwd; /// did we do AAAA update for this lease?
|
||||
bool fqdn_rev; /// did we do PTR update for this lease?
|
||||
std::string options; /// additional options stored with this lease
|
||||
/// (currently not used)
|
||||
std::string comments; /// comments on that lease
|
||||
/// (currently not used)
|
||||
};
|
||||
|
||||
/// Pointer to a Lease4 structure
|
||||
typedef boost::shared_ptr<Lease4> Lease4Ptr;
|
||||
|
||||
/// an implementation of in-memory+file database
|
||||
/// The actual implementation is in memfile_ubench.cc
|
||||
class memfile_LeaseMgr;
|
||||
|
||||
/// @brief In-memory + file micro-benchmark.
|
||||
///
|
||||
/// That is a specific backend implementation. See \ref uBenchmark class for
|
||||
/// detailed explanation of its operations. This class uses custom in-memory
|
||||
/// pseudo-database and external write-only lease file. That approach simulates
|
||||
/// modernized model of ISC DHCP4. It uses standard STL maps together with
|
||||
/// shared_ptr from boost library. The "database" is implemented in the Lease
|
||||
/// Manager (see \ref LeaseMgr in memfile_ubench.cc). All lease changes are
|
||||
/// appended to the end of the file, speeding up the process.
|
||||
class memfile_uBenchmark: public uBenchmark {
|
||||
public:
|
||||
|
||||
/// @brief The sole memfile benchmark constructor.
|
||||
///
|
||||
/// @param filename name of the write-only lease file
|
||||
/// @param num_iterations number of iterations
|
||||
/// @param sync should fsync() be called after every file write?
|
||||
/// @param verbose would you like extra logging?
|
||||
memfile_uBenchmark(const std::string& filename,
|
||||
uint32_t num_iterations, bool sync, bool verbose);
|
||||
|
||||
/// @brief Prints backend info.
|
||||
virtual void printInfo();
|
||||
|
||||
/// @brief Spawns lease manager that create empty lease file, initializes
|
||||
/// empty STL maps.
|
||||
virtual void connect();
|
||||
|
||||
/// @brief Delete lease manager that closes lease file.
|
||||
virtual void disconnect();
|
||||
|
||||
/// @brief Creates new leases.
|
||||
///
|
||||
/// See uBenchmark::createLease4Test() for detailed explanation.
|
||||
virtual void createLease4Test();
|
||||
|
||||
/// @brief Searches for existing leases.
|
||||
///
|
||||
/// See uBenchmark::searchLease4Test() for detailed explanation.
|
||||
virtual void searchLease4Test();
|
||||
|
||||
/// @brief Updates existing leases.
|
||||
///
|
||||
/// See uBenchmark::updateLease4Test() for detailed explanation.
|
||||
virtual void updateLease4Test();
|
||||
|
||||
/// @brief Deletes existing leases.
|
||||
///
|
||||
/// See uBenchmark::deleteLease4Test() for detailed explanation.
|
||||
virtual void deleteLease4Test();
|
||||
|
||||
protected:
|
||||
|
||||
/// Lease Manager (concrete backend implementation, based on STL maps)
|
||||
memfile_LeaseMgr * leaseMgr_;
|
||||
};
|
@ -1,86 +0,0 @@
|
||||
DROP DATABASE kea;
|
||||
CREATE DATABASE kea;
|
||||
|
||||
CONNECT kea;
|
||||
|
||||
CREATE TABLE lease4 (
|
||||
|
||||
# Primary key (serial = BININT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE)
|
||||
lease_id SERIAL,
|
||||
addr INT UNSIGNED UNIQUE,
|
||||
|
||||
# The largest hardware address is for Infiniband (20 bytes)
|
||||
hwaddr VARCHAR(20),
|
||||
|
||||
# The largest client-id is DUID in DHCPv6 - up to 128 bytes
|
||||
client_id VARCHAR(128),
|
||||
|
||||
# Expressed in seconds
|
||||
valid_lft INT,
|
||||
|
||||
# Expressed in seconds,
|
||||
recycle_time INT DEFAULT 0,
|
||||
|
||||
cltt TIMESTAMP,
|
||||
|
||||
pool_id int,
|
||||
|
||||
fixed BOOL,
|
||||
|
||||
# DDNS stuff
|
||||
hostname VARCHAR(255),
|
||||
fqdn_fwd BOOL DEFAULT false,
|
||||
fqdn_rev BOOL DEFAULT false,
|
||||
|
||||
options TEXT,
|
||||
comments TEXT
|
||||
);
|
||||
|
||||
CREATE TABLE lease6 (
|
||||
|
||||
# Primary key (serial = BININT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE)
|
||||
lease_id SERIAL,
|
||||
addr CHAR(16) BYTE UNIQUE,
|
||||
|
||||
# The largest hardware address is for Infiniband (20 bytes)
|
||||
hwaddr VARCHAR(20),
|
||||
|
||||
# The largest client-id is DUID in DHCPv6 - up to 128 bytes
|
||||
client_id VARCHAR(128),
|
||||
|
||||
iaid int unsigned,
|
||||
|
||||
# Used for IA_PD only (tinyint = 0..255)
|
||||
prefix_len TINYINT unsigned,
|
||||
|
||||
# Expressed in seconds
|
||||
preferred_lft INT,
|
||||
|
||||
# Expressed in seconds
|
||||
valid_lft INT,
|
||||
|
||||
# Expressed in seconds,
|
||||
recycle_time INT DEFAULT 0,
|
||||
|
||||
cltt TIMESTAMP,
|
||||
|
||||
pool_id int,
|
||||
|
||||
fixed BOOL DEFAULT false,
|
||||
|
||||
hostname VARCHAR(255),
|
||||
fqdn_fwd BOOL DEFAULT false,
|
||||
fqdn_rev BOOL DEFAULT false,
|
||||
|
||||
options TEXT,
|
||||
comments TEXT
|
||||
);
|
||||
|
||||
CREATE TABLE host (
|
||||
address BIGINT NULL,
|
||||
address6 BIGINT NULL,
|
||||
prefix6 BIGINT NULL,
|
||||
hostname VARCHAR(255),
|
||||
options TEXT,
|
||||
comments TEXT
|
||||
);
|
@ -1,674 +0,0 @@
|
||||
// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <mysql.h>
|
||||
|
||||
#include "benchmark.h"
|
||||
#include "mysql_ubench.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
MySQL_uBenchmark::MySQL_uBenchmark(const string& hostname, const string& user,
|
||||
const string& pass, const string& db,
|
||||
uint32_t num_iterations, bool sync,
|
||||
bool verbose)
|
||||
:uBenchmark(num_iterations, db, sync, verbose, hostname, user, pass),
|
||||
conn_(NULL) {
|
||||
|
||||
}
|
||||
|
||||
void MySQL_uBenchmark::stmt_failure(MYSQL_STMT * stmt, const char* operation) {
|
||||
stringstream tmp;
|
||||
tmp << "Error " << mysql_stmt_errno(stmt) << " during " << operation
|
||||
<< ": " << mysql_stmt_error(stmt);
|
||||
throw tmp.str();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void MySQL_uBenchmark::failure(const char* operation) {
|
||||
stringstream tmp;
|
||||
tmp << "Error " << mysql_errno(conn_) << " during " << operation
|
||||
<< ": " << mysql_error(conn_);
|
||||
throw tmp.str();
|
||||
}
|
||||
|
||||
void MySQL_uBenchmark::connect() {
|
||||
|
||||
conn_ = mysql_init(NULL);
|
||||
if (!conn_) {
|
||||
failure("initializing MySQL library");
|
||||
} else {
|
||||
cout << "MySQL library init successful." << endl;
|
||||
}
|
||||
|
||||
if (!mysql_real_connect(conn_, hostname_.c_str(), user_.c_str(),
|
||||
passwd_.c_str(), dbname_.c_str(), 0, NULL, 0)) {
|
||||
failure("connecting to MySQL server");
|
||||
} else {
|
||||
cout << "MySQL connection established." << endl;
|
||||
}
|
||||
|
||||
string q = "delete from lease4;";
|
||||
if (mysql_real_query(conn_, q.c_str(), strlen(q.c_str()))) {
|
||||
failure("dropping old lease4 entries.");
|
||||
}
|
||||
|
||||
q = "ALTER TABLE lease4 engine=";
|
||||
if (sync_) {
|
||||
q += "InnoDB";
|
||||
} else {
|
||||
q += "MyISAM";
|
||||
}
|
||||
if (mysql_query(conn_, q.c_str())) {
|
||||
q = "Failed to run query:" + q;
|
||||
failure(q.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void MySQL_uBenchmark::disconnect() {
|
||||
if (!conn_) {
|
||||
throw "NULL MySQL connection pointer.";
|
||||
}
|
||||
mysql_close(conn_);
|
||||
conn_ = NULL;
|
||||
}
|
||||
|
||||
void MySQL_uBenchmark::createLease4Test() {
|
||||
if (!conn_) {
|
||||
throw "Not connected to MySQL server.";
|
||||
}
|
||||
|
||||
uint32_t addr = BASE_ADDR4; // Let's start with 1.0.0.0 address
|
||||
char hwaddr[20];
|
||||
size_t hwaddr_len = 20; // Not a real field
|
||||
char client_id[128];
|
||||
size_t client_id_len = 128;
|
||||
uint32_t valid_lft = 1000; // We can use the same value for all leases
|
||||
uint32_t recycle_time = 7; // not supported in any foresable future,
|
||||
|
||||
char cltt[48]; // timestamp (specified as text)
|
||||
size_t cltt_len;
|
||||
|
||||
sprintf(cltt, "2012-07-11 15:43:00");
|
||||
cltt_len = strlen(cltt);
|
||||
|
||||
uint32_t pool_id = 1000; // Let's use pool-ids greater than zero
|
||||
bool fixed = false;
|
||||
|
||||
char hostname[] = "foo"; // Will generate it dynamically
|
||||
size_t hostname_len;
|
||||
hostname_len = strlen(hostname);
|
||||
|
||||
bool fqdn_fwd = true; // Let's pretend to do AAAA update
|
||||
bool fqdn_rev = true; // Let's pretend to do PTR update
|
||||
|
||||
cout << "CREATE: ";
|
||||
|
||||
for (uint8_t i = 0; i < hwaddr_len; i++) {
|
||||
hwaddr[i] = 'A' + i; // let's make hwaddr consisting of letters
|
||||
}
|
||||
hwaddr[19] = 0; // make it is null-terminated
|
||||
|
||||
for (uint8_t i = 0; i < client_id_len; i++) {
|
||||
client_id[i] = 33 + i; // 33 is being the first, non whitespace
|
||||
// printable ASCII character
|
||||
}
|
||||
client_id[127] = 0; // make it is null-terminated
|
||||
|
||||
MYSQL_STMT * stmt = NULL;
|
||||
MYSQL_BIND bind[11]; // 11 parameters in the insert statement
|
||||
|
||||
if (compiled_stmt_) {
|
||||
// create a statement once
|
||||
stmt = mysql_stmt_init(conn_);
|
||||
if (!stmt) {
|
||||
failure("Unable to create compiled statement, mysql_stmt_init() failed");
|
||||
}
|
||||
|
||||
const char * statement = "INSERT INTO lease4(addr,hwaddr,client_id,"
|
||||
"valid_lft,recycle_time,cltt,pool_id,fixed,hostname,"
|
||||
"fqdn_fwd,fqdn_rev) VALUES(?,?,?,?,?,?,?,?,?,?,?)";
|
||||
|
||||
if (mysql_stmt_prepare(stmt, statement, strlen(statement) )) {
|
||||
failure("Failed to prepare statement, mysql_stmt_prepare() returned non-zero");
|
||||
}
|
||||
int param_cnt = mysql_stmt_param_count(stmt);
|
||||
if (param_cnt != 11) {
|
||||
failure("Parameter count sanity check failed.");
|
||||
}
|
||||
|
||||
memset(bind, 0, sizeof(bind));
|
||||
|
||||
// 1st parameter: IPv4 address
|
||||
bind[0].buffer_type = MYSQL_TYPE_LONG;
|
||||
bind[0].buffer = (&addr);
|
||||
bind[0].is_null = 0;
|
||||
bind[0].length = 0;
|
||||
|
||||
// 2nd parameter: Hardware address
|
||||
bind[1].buffer_type = MYSQL_TYPE_VARCHAR;
|
||||
bind[1].buffer = hwaddr;
|
||||
bind[1].buffer_length = hwaddr_len;
|
||||
bind[1].is_null = 0;
|
||||
bind[1].length = &hwaddr_len;
|
||||
|
||||
// 3rd parameter: Client-id
|
||||
bind[2].buffer_type = MYSQL_TYPE_VARCHAR;
|
||||
bind[2].buffer = client_id;
|
||||
bind[2].buffer_length = client_id_len;
|
||||
bind[2].is_null = 0;
|
||||
bind[2].length = &client_id_len;
|
||||
|
||||
// 4th parameter: valid-lifetime
|
||||
bind[3].buffer_type = MYSQL_TYPE_LONG;
|
||||
bind[3].buffer = (&valid_lft);
|
||||
bind[3].is_null = 0;
|
||||
bind[3].length = 0;
|
||||
|
||||
// 5th parameter: recycle-time
|
||||
bind[4].buffer_type = MYSQL_TYPE_LONG;
|
||||
bind[4].buffer = (&recycle_time);
|
||||
bind[4].is_null = 0;
|
||||
bind[4].length = 0;
|
||||
|
||||
// 6th parameter: cltt
|
||||
bind[5].buffer_type = MYSQL_TYPE_TIMESTAMP;
|
||||
bind[5].buffer = cltt;
|
||||
bind[2].buffer_length = cltt_len;
|
||||
bind[5].is_null = 0;
|
||||
bind[5].length = &cltt_len;
|
||||
|
||||
// 7th parameter: pool-id
|
||||
bind[6].buffer_type = MYSQL_TYPE_LONG;
|
||||
bind[6].buffer = &pool_id;
|
||||
bind[6].is_null = 0;
|
||||
bind[6].length = 0;
|
||||
|
||||
// 8th parameter: fixed
|
||||
bind[7].buffer_type = MYSQL_TYPE_TINY;
|
||||
bind[7].buffer = &fixed;
|
||||
bind[7].is_null = 0;
|
||||
bind[7].length = 0;
|
||||
|
||||
// 9th parameter: hostname
|
||||
bind[8].buffer_type = MYSQL_TYPE_VARCHAR;
|
||||
bind[8].buffer = hostname;
|
||||
bind[8].buffer_length = strlen(hostname);
|
||||
bind[8].is_null = 0;
|
||||
bind[8].length = &hostname_len;
|
||||
|
||||
// 10th parameter: fqdn_fwd
|
||||
bind[9].buffer_type = MYSQL_TYPE_TINY;
|
||||
bind[9].buffer = &fqdn_fwd;
|
||||
bind[9].is_null = 0;
|
||||
bind[9].length = 0;
|
||||
|
||||
// 11th parameter: fqdn_rev
|
||||
bind[10].buffer_type = MYSQL_TYPE_TINY;
|
||||
bind[10].buffer = &fqdn_rev;
|
||||
bind[10].is_null = 0;
|
||||
bind[10].length = 0;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < num_; i++) {
|
||||
|
||||
sprintf(cltt, "2012-07-11 15:43:%02d", i % 60);
|
||||
|
||||
|
||||
addr++;
|
||||
|
||||
if (!compiled_stmt_) {
|
||||
// the first address is 1.0.0.0.
|
||||
char query[2000], * end;
|
||||
strcpy(query, "INSERT INTO lease4(addr,hwaddr,client_id,"
|
||||
"valid_lft,recycle_time,cltt,pool_id,fixed,hostname,"
|
||||
"fqdn_fwd,fqdn_rev) VALUES(");
|
||||
end = query + strlen(query);
|
||||
end += sprintf(end, "%u,\'", addr);
|
||||
end += mysql_real_escape_string(conn_, end, hwaddr, hwaddr_len);
|
||||
end += sprintf(end,"\',\'");
|
||||
end += mysql_real_escape_string(conn_, end, client_id, client_id_len);
|
||||
end += sprintf(end, "\',%d,%d,'%s',%d,%s,\'%s\',%s,%s);",
|
||||
valid_lft, recycle_time, cltt,
|
||||
pool_id, (fixed?"true":"false"), hostname,
|
||||
(fqdn_fwd?"true":"false"), (fqdn_rev?"true":"false"));
|
||||
// lease_id field is set automatically
|
||||
// options and comments fields are not set
|
||||
|
||||
unsigned int len = end - query;
|
||||
if (mysql_real_query(conn_, query, len)) {
|
||||
// something failed.
|
||||
failure("INSERT query");
|
||||
}
|
||||
} else {
|
||||
// compiled statement
|
||||
|
||||
if (mysql_stmt_bind_param(stmt, bind)) {
|
||||
failure("Failed to bind parameters: mysql_stmt_bind_param() returned non-zero");
|
||||
}
|
||||
|
||||
if (mysql_stmt_execute(stmt)) {
|
||||
failure("Failed to execute statement: mysql_stmt_execute() returned non-zero");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (verbose_) {
|
||||
cout << ".";
|
||||
}
|
||||
}
|
||||
|
||||
if (compiled_stmt_) {
|
||||
if (mysql_stmt_close(stmt)) {
|
||||
failure("Failed to close compiled statement, mysql_stmt_close returned non-zero");
|
||||
}
|
||||
}
|
||||
|
||||
cout << endl;
|
||||
}
|
||||
|
||||
void MySQL_uBenchmark::searchLease4Test() {
|
||||
if (!conn_) {
|
||||
throw "Not connected to MySQL server.";
|
||||
}
|
||||
|
||||
cout << "RETRIEVE: ";
|
||||
|
||||
uint32_t addr = 0;
|
||||
|
||||
MYSQL_STMT * stmt = NULL;
|
||||
MYSQL_BIND bind[1]; // just a single element
|
||||
if (compiled_stmt_) {
|
||||
stmt = mysql_stmt_init(conn_);
|
||||
if (!stmt) {
|
||||
failure("Unable to create compiled statement");
|
||||
}
|
||||
const char * statement = "SELECT lease_id,addr,hwaddr,client_id,"
|
||||
"valid_lft, cltt,pool_id,fixed,hostname,fqdn_fwd,fqdn_rev "
|
||||
"FROM lease4 where addr=?";
|
||||
if (mysql_stmt_prepare(stmt, statement, strlen(statement))) {
|
||||
failure("Failed to prepare statement, mysql_stmt_prepare() returned non-zero");
|
||||
}
|
||||
int param_cnt = mysql_stmt_param_count(stmt);
|
||||
if (param_cnt != 1) {
|
||||
failure("Parameter count sanity check failed.");
|
||||
}
|
||||
|
||||
memset(bind, 0, sizeof(bind));
|
||||
|
||||
// 1st parameter: IPv4 address
|
||||
bind[0].buffer_type = MYSQL_TYPE_LONG;
|
||||
bind[0].buffer = (&addr);
|
||||
bind[0].is_null = 0;
|
||||
bind[0].length = 0;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < num_; i++) {
|
||||
|
||||
addr = BASE_ADDR4 + random() % int(num_ / hitratio_);
|
||||
|
||||
if (!compiled_stmt_) {
|
||||
char query[512];
|
||||
sprintf(query, "SELECT lease_id,addr,hwaddr,client_id,valid_lft,"
|
||||
"cltt,pool_id,fixed,hostname,fqdn_fwd,fqdn_rev "
|
||||
"FROM lease4 where addr=%d", addr);
|
||||
mysql_real_query(conn_, query, strlen(query));
|
||||
|
||||
MYSQL_RES * result = mysql_store_result(conn_);
|
||||
|
||||
int num_rows = mysql_num_rows(result);
|
||||
int num_fields = mysql_num_fields(result);
|
||||
|
||||
if ( (num_rows > 1) ) {
|
||||
stringstream tmp;
|
||||
tmp << "Search: DB returned " << num_rows << " leases for address "
|
||||
<< hex << addr << dec;
|
||||
failure(tmp.str().c_str());
|
||||
}
|
||||
|
||||
if (num_rows) {
|
||||
if (num_fields == 0) {
|
||||
failure("Query returned empty set");
|
||||
}
|
||||
|
||||
MYSQL_ROW row = mysql_fetch_row(result);
|
||||
|
||||
// pretend to do something with it
|
||||
if (row[0] == NULL) {
|
||||
failure("SELECT returned NULL data.");
|
||||
}
|
||||
mysql_free_result(result);
|
||||
|
||||
if (verbose_) {
|
||||
cout << "."; // hit
|
||||
}
|
||||
|
||||
} else {
|
||||
if (verbose_) {
|
||||
cout << "x"; // miss
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// compiled statement
|
||||
|
||||
if (mysql_stmt_bind_param(stmt, bind)) {
|
||||
failure("Failed to bind parameters: mysql_stmt_bind_param() returned non-zero");
|
||||
}
|
||||
|
||||
if (mysql_stmt_execute(stmt)) {
|
||||
failure("Failed to execute statement: mysql_stmt_execute() returned non-zero");
|
||||
}
|
||||
|
||||
MYSQL_BIND response[11];
|
||||
|
||||
size_t length[11];
|
||||
my_bool is_null[11];
|
||||
my_bool error[11];
|
||||
|
||||
uint32_t lease_id;
|
||||
uint32_t lease_addr;
|
||||
char hwaddr[20];
|
||||
char client_id[128];
|
||||
uint32_t valid_lft; // We can use the same value for all leases
|
||||
MYSQL_TIME cltt;
|
||||
uint32_t pool_id;
|
||||
my_bool fixed;
|
||||
char hostname[255];
|
||||
my_bool fqdn_fwd;
|
||||
my_bool fqdn_rev;
|
||||
|
||||
for (int j = 0; j < 11; j++) {
|
||||
response[j].is_null = &is_null[j];
|
||||
response[j].length = &length[j];
|
||||
response[j].error = &error[j];
|
||||
}
|
||||
|
||||
// 1th parameter: lease_id
|
||||
response[0].buffer_type = MYSQL_TYPE_LONG;
|
||||
response[0].buffer = (&lease_id);
|
||||
|
||||
// 2nd parameter: IPv4 address
|
||||
response[1].buffer_type = MYSQL_TYPE_LONG;
|
||||
response[1].buffer = (&lease_addr);
|
||||
|
||||
// 3rd parameter: Hardware address
|
||||
response[2].buffer_type = MYSQL_TYPE_STRING;
|
||||
response[2].buffer = hwaddr;
|
||||
response[2].buffer_length = sizeof(hwaddr);
|
||||
|
||||
// 4th parameter: Client-id
|
||||
response[3].buffer_type = MYSQL_TYPE_STRING;
|
||||
response[3].buffer = &client_id;
|
||||
response[3].buffer_length = sizeof(client_id);
|
||||
|
||||
// 5th parameter: valid-lifetime
|
||||
response[4].buffer_type = MYSQL_TYPE_LONG;
|
||||
response[4].buffer = &valid_lft;
|
||||
|
||||
// 6th parameter: cltt
|
||||
response[5].buffer_type = MYSQL_TYPE_TIMESTAMP;
|
||||
response[5].buffer = &cltt;
|
||||
|
||||
// 7th parameter: pool-id
|
||||
response[6].buffer_type = MYSQL_TYPE_LONG;
|
||||
response[6].buffer = &pool_id;
|
||||
|
||||
// 8th parameter: fixed
|
||||
response[7].buffer_type = MYSQL_TYPE_TINY;
|
||||
response[7].buffer = &fixed;
|
||||
|
||||
// 9th parameter: hostname
|
||||
response[8].buffer_type = MYSQL_TYPE_STRING;
|
||||
response[8].buffer = &hostname;
|
||||
|
||||
// 10th parameter: fqdn_fwd
|
||||
response[9].buffer_type = MYSQL_TYPE_TINY;
|
||||
response[9].buffer = &fqdn_fwd;
|
||||
|
||||
// 11th parameter: fqdn_rev
|
||||
response[10].buffer_type = MYSQL_TYPE_TINY;
|
||||
response[10].buffer = &fqdn_rev;
|
||||
|
||||
if (mysql_stmt_bind_result(stmt, response))
|
||||
{
|
||||
cout << "Error:" << mysql_stmt_error(stmt) << endl;
|
||||
failure("mysql_stmt_bind_result() failed");
|
||||
}
|
||||
int num_rows = 0;
|
||||
|
||||
int result = mysql_stmt_fetch(stmt);
|
||||
switch (result) {
|
||||
case 0: {
|
||||
if (lease_addr != addr) {
|
||||
failure("Returned data is bogus!");
|
||||
}
|
||||
num_rows++;
|
||||
break;
|
||||
}
|
||||
case MYSQL_NO_DATA:
|
||||
{
|
||||
// that's ok. We randomized non-existing address
|
||||
break;
|
||||
|
||||
}
|
||||
default: {
|
||||
stmt_failure(stmt, "RETRIEVE (mysql_stmt_fetch())");
|
||||
}
|
||||
}
|
||||
|
||||
// we could call mysql_stmt_fetch again to check that there are no
|
||||
// other data for us. But there should be exactly one row of data
|
||||
// with specified address.
|
||||
|
||||
if (num_rows) {
|
||||
if (verbose_) {
|
||||
cout << "."; // hit
|
||||
}
|
||||
} else {
|
||||
if (verbose_) {
|
||||
cout << "X"; // miss
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (compiled_stmt_) {
|
||||
if (mysql_stmt_close(stmt)) {
|
||||
failure("Failed to close compiled statement, mysql_stmt_close returned non-zero");
|
||||
}
|
||||
}
|
||||
|
||||
cout << endl;
|
||||
}
|
||||
|
||||
void MySQL_uBenchmark::updateLease4Test() {
|
||||
if (!conn_) {
|
||||
throw "Not connected to MySQL server.";
|
||||
}
|
||||
|
||||
cout << "UPDATE: ";
|
||||
|
||||
uint32_t valid_lft = 1002; // just some dummy value
|
||||
char cltt[] = "now()";
|
||||
size_t cltt_len = strlen(cltt);
|
||||
uint32_t addr = 0;
|
||||
|
||||
MYSQL_STMT * stmt = NULL;
|
||||
MYSQL_BIND bind[3];
|
||||
if (compiled_stmt_) {
|
||||
stmt = mysql_stmt_init(conn_);
|
||||
if (!stmt) {
|
||||
failure("Unable to create compiled statement");
|
||||
}
|
||||
const char * statement = "UPDATE lease4 SET valid_lft=?, cltt=? WHERE addr=?";
|
||||
if (mysql_stmt_prepare(stmt, statement, strlen(statement))) {
|
||||
failure("Failed to prepare statement, mysql_stmt_prepare() returned non-zero");
|
||||
}
|
||||
int param_cnt = mysql_stmt_param_count(stmt);
|
||||
if (param_cnt != 3) {
|
||||
failure("Parameter count sanity check failed.");
|
||||
}
|
||||
|
||||
memset(bind, 0, sizeof(bind));
|
||||
|
||||
// 1st parameter: valid lifetime
|
||||
bind[0].buffer_type = MYSQL_TYPE_LONG;
|
||||
bind[0].buffer = &valid_lft;
|
||||
|
||||
// 2nd parameter: cltt
|
||||
bind[1].buffer_type = MYSQL_TYPE_STRING;
|
||||
bind[1].buffer = &cltt;
|
||||
bind[1].buffer_length = cltt_len;
|
||||
|
||||
bind[2].buffer_type = MYSQL_TYPE_LONG;
|
||||
bind[2].buffer = &addr;
|
||||
}
|
||||
|
||||
|
||||
for (uint32_t i = 0; i < num_; i++) {
|
||||
|
||||
addr = BASE_ADDR4 + random() % num_;
|
||||
|
||||
if (!compiled_stmt_) {
|
||||
char query[128];
|
||||
sprintf(query, "UPDATE lease4 SET valid_lft=1002, cltt=now() WHERE addr=%d", addr);
|
||||
mysql_real_query(conn_, query, strlen(query));
|
||||
|
||||
} else {
|
||||
// compiled statement
|
||||
if (mysql_stmt_bind_param(stmt, bind)) {
|
||||
failure("Failed to bind parameters: mysql_stmt_bind_param() returned non-zero");
|
||||
}
|
||||
|
||||
if (mysql_stmt_execute(stmt)) {
|
||||
failure("Failed to execute statement: mysql_stmt_execute() returned non-zero");
|
||||
}
|
||||
}
|
||||
|
||||
if (verbose_) {
|
||||
cout << ".";
|
||||
}
|
||||
}
|
||||
|
||||
if (compiled_stmt_) {
|
||||
if (mysql_stmt_close(stmt)) {
|
||||
failure("Failed to close compiled statement, mysql_stmt_close returned non-zero");
|
||||
}
|
||||
}
|
||||
|
||||
cout << endl;
|
||||
}
|
||||
|
||||
void MySQL_uBenchmark::deleteLease4Test() {
|
||||
if (!conn_) {
|
||||
throw "Not connected to MySQL server.";
|
||||
}
|
||||
|
||||
cout << "DELETE: ";
|
||||
|
||||
uint32_t addr = 0;
|
||||
|
||||
MYSQL_STMT * stmt = NULL;
|
||||
MYSQL_BIND bind[1]; // just a single element
|
||||
if (compiled_stmt_) {
|
||||
|
||||
stmt = mysql_stmt_init(conn_);
|
||||
if (!stmt) {
|
||||
failure("Unable to create compiled statement, mysql_stmt_init() failed");
|
||||
}
|
||||
|
||||
const char * statement = "DELETE FROM lease4 WHERE addr=?";
|
||||
|
||||
if (mysql_stmt_prepare(stmt, statement, strlen(statement) )) {
|
||||
failure("Failed to prepare statement, mysql_stmt_prepare() returned non-zero");
|
||||
}
|
||||
int param_cnt = mysql_stmt_param_count(stmt);
|
||||
if (param_cnt != 1) {
|
||||
failure("Parameter count sanity check failed.");
|
||||
}
|
||||
|
||||
memset(bind, 0, sizeof(bind));
|
||||
|
||||
// 1st parameter: IPv4 address
|
||||
bind[0].buffer_type = MYSQL_TYPE_LONG;
|
||||
bind[0].buffer = (&addr);
|
||||
bind[0].is_null = 0;
|
||||
bind[0].length = 0;
|
||||
}
|
||||
|
||||
|
||||
for (uint32_t i = 0; i < num_; i++) {
|
||||
|
||||
addr = BASE_ADDR4 + i;
|
||||
|
||||
if (!compiled_stmt_) {
|
||||
char query[128];
|
||||
sprintf(query, "DELETE FROM lease4 WHERE addr=%d", addr);
|
||||
mysql_real_query(conn_, query, strlen(query));
|
||||
} else {
|
||||
// compiled statement
|
||||
if (mysql_stmt_bind_param(stmt, bind)) {
|
||||
failure("Failed to bind parameters: mysql_stmt_bind_param() returned non-zero");
|
||||
}
|
||||
|
||||
if (mysql_stmt_execute(stmt)) {
|
||||
failure("Failed to execute statement: mysql_stmt_execute() returned non-zero");
|
||||
}
|
||||
}
|
||||
|
||||
if (verbose_) {
|
||||
cout << ".";
|
||||
}
|
||||
}
|
||||
|
||||
if (compiled_stmt_) {
|
||||
if (mysql_stmt_close(stmt)) {
|
||||
failure("Failed to close compiled statement, mysql_stmt_close returned non-zero");
|
||||
}
|
||||
}
|
||||
|
||||
cout << endl;
|
||||
}
|
||||
|
||||
void MySQL_uBenchmark::printInfo() {
|
||||
cout << "MySQL client version is " << mysql_get_client_info() << endl;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char * const argv[]) {
|
||||
|
||||
const char* hostname ="localhost"; // -m (MySQL server)
|
||||
const char* user = "root"; // -u
|
||||
const char* passwd = "secret"; // -p
|
||||
const char* dbname = "kea"; // -f
|
||||
uint32_t num = 100; // -n
|
||||
bool sync = true; // -s
|
||||
bool verbose = true; // -v
|
||||
|
||||
MySQL_uBenchmark bench(hostname, user, passwd, dbname, num, sync, verbose);
|
||||
|
||||
bench.parseCmdline(argc, argv);
|
||||
|
||||
int result = bench.run();
|
||||
|
||||
return (result);
|
||||
}
|
@ -1,104 +0,0 @@
|
||||
// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
#include <string>
|
||||
#include "benchmark.h"
|
||||
|
||||
/// @brief MySQL micro-benchmark.
|
||||
///
|
||||
/// That is a specific backend implementation. See \ref uBenchmark class for
|
||||
/// detailed explanation of its operations. This class uses MySQL as database
|
||||
/// backend.
|
||||
class MySQL_uBenchmark: public uBenchmark {
|
||||
public:
|
||||
|
||||
/// @brief The sole MySQL micro-benchmark constructor
|
||||
///
|
||||
/// To avoid influence of network performance, it is highly recommended
|
||||
/// to run MySQL engine on the same host as benchmark. Thus hostname
|
||||
/// is likely to be "localhost". Make sure that the selected database
|
||||
/// is already created and that it follows expected schema. See mysql.schema
|
||||
/// and isc-dhcp-perf-guide.html for details.
|
||||
///
|
||||
/// Synchronous operation means using InnDB, async is MyISAM.
|
||||
///
|
||||
/// @param hostname Name of the host to connect to
|
||||
/// @param user usename used during MySQL connection
|
||||
/// @param pass password used during MySQL connection
|
||||
/// @param db name of the database to connect to
|
||||
/// @param num_iterations number of iterations for basic operations
|
||||
/// @param sync synchronous or asynchronous database writes
|
||||
/// @param verbose should extra information be logged?
|
||||
MySQL_uBenchmark(const std::string& hostname, const std::string& user,
|
||||
const std::string& pass, const std::string& db,
|
||||
uint32_t num_iterations, bool sync,
|
||||
bool verbose);
|
||||
|
||||
/// @brief Prints MySQL version info.
|
||||
virtual void printInfo();
|
||||
|
||||
/// @brief Opens connection to the MySQL database.
|
||||
virtual void connect();
|
||||
|
||||
/// @brief Closes connection to the MySQL database.
|
||||
virtual void disconnect();
|
||||
|
||||
/// @brief Creates new leases.
|
||||
///
|
||||
/// See uBenchmark::createLease4Test() for detailed explanation.
|
||||
virtual void createLease4Test();
|
||||
|
||||
/// @brief Searches for existing leases.
|
||||
///
|
||||
/// See uBenchmark::searchLease4Test() for detailed explanation.
|
||||
virtual void searchLease4Test();
|
||||
|
||||
/// @brief Updates existing leases.
|
||||
///
|
||||
/// See uBenchmark::updateLease4Test() for detailed explanation.
|
||||
virtual void updateLease4Test();
|
||||
|
||||
/// @brief Deletes existing leases.
|
||||
///
|
||||
/// See uBenchmark::deleteLease4Test() for detailed explanation.
|
||||
virtual void deleteLease4Test();
|
||||
|
||||
protected:
|
||||
/// @brief Used to report any database failures.
|
||||
///
|
||||
/// Compared to its base version in uBenchmark class, this one logs additional
|
||||
/// MySQL specific information using mysql_errno() and mysql_error() functions.
|
||||
/// The outcome is the same: exception is thrown.
|
||||
///
|
||||
/// @param operation brief description of the operation that caused error
|
||||
///
|
||||
/// @sa stmt_failure()
|
||||
void failure(const char* operation);
|
||||
|
||||
/// @brief Used to report compiled statement failures.
|
||||
///
|
||||
/// Compared to its base version in uBenchmark class, this one logs additional
|
||||
/// MySQL specific information using mysql_stmt_errno() and mysql_stmt_error()
|
||||
/// functions that are used for compiled statements error reporting.
|
||||
///
|
||||
/// @param stmt MySQL compiled statement structure
|
||||
/// @param operation brief description of the operation that caused error
|
||||
///
|
||||
/// @sa failure()
|
||||
void stmt_failure(MYSQL_STMT * stmt, const char* operation);
|
||||
|
||||
|
||||
/// Handle to MySQL database connection.
|
||||
MYSQL* conn_;
|
||||
};
|
Binary file not shown.
Before Width: | Height: | Size: 38 KiB |
Binary file not shown.
Before Width: | Height: | Size: 38 KiB |
Binary file not shown.
@ -1,85 +0,0 @@
|
||||
DROP TABLE lease4;
|
||||
DROP TABLE lease6;
|
||||
DROP TABLE host;
|
||||
|
||||
CREATE TABLE lease4 (
|
||||
|
||||
-- Primary key (serial = BININT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE)
|
||||
lease_id SERIAL,
|
||||
addr INT UNSIGNED UNIQUE,
|
||||
|
||||
-- The largest hardware address is for Infiniband (20 bytes)
|
||||
hwaddr VARCHAR(20),
|
||||
|
||||
-- The largest client-id is DUID in DHCPv6 - up to 128 bytes
|
||||
client_id VARCHAR(128),
|
||||
|
||||
-- Expressed in seconds
|
||||
valid_lft INT,
|
||||
|
||||
-- Expressed in seconds,
|
||||
recycle_time INT DEFAULT 0,
|
||||
|
||||
cltt TIMESTAMP,
|
||||
|
||||
pool_id int,
|
||||
|
||||
fixed BOOL,
|
||||
|
||||
-- DDNS stuff
|
||||
hostname VARCHAR(255),
|
||||
fqdn_fwd BOOL DEFAULT false,
|
||||
fqdn_rev BOOL DEFAULT false,
|
||||
|
||||
options TEXT,
|
||||
comments TEXT
|
||||
);
|
||||
|
||||
CREATE TABLE lease6 (
|
||||
|
||||
-- Primary key (serial = BININT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE)
|
||||
lease_id SERIAL,
|
||||
addr CHAR(16) UNIQUE,
|
||||
|
||||
-- The largest hardware address is for Infiniband (20 bytes)
|
||||
hwaddr VARCHAR(20),
|
||||
|
||||
-- The largest client-id is DUID in DHCPv6 - up to 128 bytes
|
||||
client_id VARCHAR(128),
|
||||
|
||||
iaid int unsigned,
|
||||
|
||||
-- Used for IA_PD only (tinyint = 0..255)
|
||||
prefix_len TINYINT unsigned,
|
||||
|
||||
-- Expressed in seconds
|
||||
preferred_lft INT,
|
||||
|
||||
-- Expressed in seconds
|
||||
valid_lft INT,
|
||||
|
||||
-- Expressed in seconds,
|
||||
recycle_time INT DEFAULT 0,
|
||||
|
||||
cltt TIMESTAMP,
|
||||
|
||||
pool_id int,
|
||||
|
||||
fixed BOOL DEFAULT false,
|
||||
|
||||
hostname VARCHAR(255),
|
||||
fqdn_fwd BOOL DEFAULT false,
|
||||
fqdn_rev BOOL DEFAULT false,
|
||||
|
||||
options TEXT,
|
||||
comments TEXT
|
||||
);
|
||||
|
||||
CREATE TABLE host (
|
||||
address BIGINT NULL,
|
||||
address6 BIGINT NULL,
|
||||
prefix6 BIGINT NULL,
|
||||
hostname VARCHAR(255),
|
||||
options TEXT,
|
||||
comments TEXT
|
||||
);
|
@ -1,513 +0,0 @@
|
||||
// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
#include <sqlite3.h>
|
||||
#include "sqlite_ubench.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
SQLite_uBenchmark::SQLite_uBenchmark(const string& filename,
|
||||
uint32_t num_iterations,
|
||||
bool sync, bool verbose)
|
||||
:uBenchmark(num_iterations, filename, sync, verbose),
|
||||
db_(NULL) {
|
||||
|
||||
}
|
||||
|
||||
void SQLite_uBenchmark::connect() {
|
||||
int result = sqlite3_open(dbname_.c_str(), &db_);
|
||||
if (result != SQLITE_OK) {
|
||||
failure("Failed to open DB file");
|
||||
}
|
||||
|
||||
result = sqlite3_exec(db_, "DELETE FROM lease4", NULL, NULL, NULL);
|
||||
if (result != SQLITE_OK) {
|
||||
failure("Failed to delete old entries");
|
||||
}
|
||||
|
||||
if (sync_) {
|
||||
sqlite3_exec(db_, "PRAGMA synchronous = ON", NULL, NULL, NULL);
|
||||
} else {
|
||||
sqlite3_exec(db_, "PRAGMA synchronous = OFF", NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
// see http://www.sqlite.org/pragma.html#pragma_journal_mode
|
||||
// for detailed explanation. Available modes: DELETE, TRUNCATE,
|
||||
// PERSIST, MEMORY, WAL, OFF
|
||||
sqlite3_exec(db_, "PRAGMA journal_mode = OFF", NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
void SQLite_uBenchmark::disconnect() {
|
||||
if (db_) {
|
||||
sqlite3_close(db_);
|
||||
db_ = NULL;
|
||||
} else {
|
||||
throw "Can't close SQLite connection: it was never open.";
|
||||
}
|
||||
}
|
||||
|
||||
void SQLite_uBenchmark::createLease4Test() {
|
||||
if (!db_) {
|
||||
throw "SQLite connection is closed.";
|
||||
}
|
||||
|
||||
uint32_t addr = BASE_ADDR4; // Let's start with 1.0.0.0 address
|
||||
const uint8_t hwaddr_len = 20; // Not a real field
|
||||
char hwaddr[hwaddr_len];
|
||||
const uint8_t client_id_len = 128;
|
||||
char client_id[client_id_len];
|
||||
uint32_t valid_lft = 1000; // We can use the same value for all leases
|
||||
uint32_t recycle_time = 0; // Not supported in any foresable future,
|
||||
// so keep this as 0
|
||||
char cltt[48]; // Timestamp
|
||||
uint32_t pool_id = 0; // Let's use pools 0-99
|
||||
bool fixed = false;
|
||||
string hostname("foo"); // Will generate it dynamically
|
||||
bool fqdn_fwd = true; // Let's pretend to do AAAA update
|
||||
bool fqdn_rev = true; // Let's pretend to do PTR update
|
||||
|
||||
cout << "CREATE: ";
|
||||
|
||||
for (uint8_t i = 0; i < hwaddr_len; i++) {
|
||||
hwaddr[i] = 65 + i;
|
||||
}
|
||||
hwaddr[19] = 0; // workaround
|
||||
|
||||
for (uint8_t i = 0; i < client_id_len; i++) {
|
||||
client_id[i] = 33 + i;
|
||||
}
|
||||
client_id[6] = 'X'; // there's apostrophe here. It would confuse
|
||||
// query formatting, let's get rid of it
|
||||
client_id[127] = 0; // workaround
|
||||
|
||||
|
||||
sqlite3_stmt *stmt = NULL;
|
||||
if (compiled_stmt_) {
|
||||
char query[] = "INSERT INTO lease4(addr,hwaddr,client_id,"
|
||||
"valid_lft,recycle_time,cltt,pool_id,fixed,hostname,"
|
||||
"fqdn_fwd,fqdn_rev) VALUES(?001,?002,?003,?004,?005,?006,?007,?008,?009,?010,?011);";
|
||||
int result = sqlite3_prepare_v2(db_, query, strlen(query), &stmt, NULL);
|
||||
if (result != SQLITE_OK) {
|
||||
failure("Failed to compile statement");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
for (uint32_t i = 0; i < num_; i++) {
|
||||
|
||||
sprintf(cltt, "2012-07-11 15:43:%02d", i % 60);
|
||||
|
||||
addr++;
|
||||
char* errorMsg = NULL;
|
||||
|
||||
if (!compiled_stmt_) {
|
||||
// the first address is 1.0.0.0.
|
||||
char query[2000];
|
||||
/// @todo: Encode HWADDR and CLIENT-ID properly
|
||||
sprintf(query, "INSERT INTO lease4(addr,hwaddr,client_id,"
|
||||
"valid_lft,recycle_time,cltt,pool_id,fixed,hostname,"
|
||||
"fqdn_fwd,fqdn_rev) VALUES(%u,'%s','%s',%d,%d,'%s',%d,'%s','%s','%s','%s');",
|
||||
addr, hwaddr, client_id, valid_lft, recycle_time,
|
||||
cltt, pool_id, (fixed?"true":"false"),
|
||||
hostname.c_str(), (fqdn_fwd?"true":"false"), (fqdn_rev?"true":"false"));
|
||||
|
||||
int result = sqlite3_exec(db_, query, NULL, 0, &errorMsg);
|
||||
|
||||
if (result != SQLITE_OK) {
|
||||
stringstream tmp;
|
||||
tmp << "INSERT error:" << errorMsg;
|
||||
failure(tmp.str().c_str());
|
||||
}
|
||||
} else {
|
||||
// compiled statement
|
||||
int result = sqlite3_bind_int(stmt, 1, addr);
|
||||
if (result != SQLITE_OK) {
|
||||
failure("sqlite3_bind_int() for column 1");
|
||||
}
|
||||
|
||||
result = sqlite3_bind_blob(stmt, 2, hwaddr, hwaddr_len, NULL);
|
||||
if (result != SQLITE_OK) {
|
||||
failure("sqlite3_bind_blob() for column 2");
|
||||
}
|
||||
|
||||
result = sqlite3_bind_blob(stmt, 3, client_id, client_id_len, NULL);
|
||||
if (result != SQLITE_OK) {
|
||||
failure("sqlite3_bind_blob() for column 3");
|
||||
}
|
||||
|
||||
if (sqlite3_bind_int(stmt, 4, valid_lft) != SQLITE_OK) {
|
||||
failure("sqlite3_bind_int() for column 4");
|
||||
}
|
||||
|
||||
if (sqlite3_bind_int(stmt, 5, recycle_time) != SQLITE_OK) {
|
||||
failure("sqlite3_bind_int() for column 5");
|
||||
}
|
||||
|
||||
if (sqlite3_bind_text(stmt, 6, cltt, strlen(cltt), NULL) != SQLITE_OK) {
|
||||
failure("sqlite3_bind_int() for column 6");
|
||||
}
|
||||
|
||||
if (sqlite3_bind_int(stmt, 7, pool_id) != SQLITE_OK) {
|
||||
failure("sqlite3_bind_int() for column 7");
|
||||
}
|
||||
|
||||
if (sqlite3_bind_int(stmt, 7, pool_id) != SQLITE_OK) {
|
||||
failure("sqlite3_bind_int() for column 7");
|
||||
}
|
||||
|
||||
if (sqlite3_bind_int(stmt, 8, fixed) != SQLITE_OK) {
|
||||
failure("sqlite3_bind_int() for column 8");
|
||||
}
|
||||
|
||||
if (sqlite3_bind_text(stmt, 9, hostname.c_str(), hostname.length(), NULL) != SQLITE_OK) {
|
||||
failure("sqlite3_bind_int() for column 9");
|
||||
}
|
||||
|
||||
if (sqlite3_bind_int(stmt, 10, fqdn_fwd) != SQLITE_OK) {
|
||||
failure("sqlite3_bind_int() for column 10");
|
||||
}
|
||||
|
||||
if (sqlite3_bind_int(stmt, 11, fqdn_rev) != SQLITE_OK) {
|
||||
failure("sqlite3_bind_int() for column 11");
|
||||
}
|
||||
|
||||
result = sqlite3_step(stmt);
|
||||
|
||||
if (result != SQLITE_DONE) {
|
||||
failure("Failed to execute INSERT clause");
|
||||
}
|
||||
|
||||
// let's reset the compiled statement, so it can be used in the
|
||||
// next iteration
|
||||
result = sqlite3_reset(stmt);
|
||||
if (result != SQLITE_OK) {
|
||||
failure("Failed to execute sqlite3_reset()");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (verbose_) {
|
||||
cout << ".";
|
||||
}
|
||||
}
|
||||
|
||||
if (compiled_stmt_) {
|
||||
int result = sqlite3_finalize(stmt);
|
||||
if (result != SQLITE_OK) {
|
||||
failure("sqlite3_finalize() failed");
|
||||
}
|
||||
}
|
||||
|
||||
cout << endl;
|
||||
}
|
||||
|
||||
static int search_callback(void *counter, int argc, char** argv,
|
||||
char** azColName){
|
||||
|
||||
int* cnt = static_cast<int*>(counter);
|
||||
(*cnt)++;
|
||||
|
||||
char buf[512];
|
||||
|
||||
// retrieved lease can be accessed here
|
||||
for(int i = 0; i < argc; i++){
|
||||
// pretend we do something with returned lease
|
||||
if (argv[i]) {
|
||||
strncpy(buf, azColName[i], 512);
|
||||
strncpy(buf, argv[i], 512);
|
||||
}
|
||||
|
||||
// Uncomment this to print out all contents
|
||||
// cout << azColName[i] << "=" << (argv[i] ? argv[i] : "NULL") << endl;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void SQLite_uBenchmark::searchLease4Test() {
|
||||
if (!db_) {
|
||||
throw "SQLite connection is closed.";
|
||||
}
|
||||
|
||||
cout << "RETRIEVE: ";
|
||||
|
||||
sqlite3_stmt *stmt = NULL;
|
||||
if (compiled_stmt_) {
|
||||
const char query[] = "SELECT lease_id,addr,hwaddr,client_id,valid_lft,"
|
||||
"cltt,pool_id,fixed,hostname,fqdn_fwd,fqdn_rev "
|
||||
"FROM lease4 where addr=?1";
|
||||
|
||||
int result = sqlite3_prepare_v2(db_, query, strlen(query), &stmt, NULL);
|
||||
if (result != SQLITE_OK) {
|
||||
failure("Failed to compile statement");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (uint32_t i = 0; i < num_; i++) {
|
||||
|
||||
uint32_t addr = BASE_ADDR4 + random() % int(num_ / hitratio_);
|
||||
|
||||
int cnt = 0;
|
||||
|
||||
if (!compiled_stmt_) {
|
||||
char* errorMsg = NULL;
|
||||
|
||||
char query[512];
|
||||
sprintf(query, "SELECT lease_id,addr,hwaddr,client_id,valid_lft,"
|
||||
"cltt,pool_id,fixed,hostname,fqdn_fwd,fqdn_rev "
|
||||
"FROM lease4 where addr=%d", addr);
|
||||
int result = sqlite3_exec(db_, query, search_callback, &cnt, &errorMsg);
|
||||
if (result != SQLITE_OK) {
|
||||
stringstream tmp;
|
||||
tmp << "SELECT failed: " << errorMsg;
|
||||
failure(tmp.str().c_str());
|
||||
}
|
||||
} else {
|
||||
// compiled statement
|
||||
int result = sqlite3_bind_int(stmt, 1, addr);
|
||||
if (result != SQLITE_OK) {
|
||||
failure("sqlite3_bind_int() for column 1");
|
||||
}
|
||||
|
||||
result = sqlite3_step(stmt);
|
||||
switch (result) {
|
||||
case SQLITE_ROW:
|
||||
{
|
||||
uint32_t lease_addr = sqlite3_column_int(stmt, 1);
|
||||
const void * lease_hwaddr = sqlite3_column_blob(stmt, 2);
|
||||
uint32_t lease_hwaddr_len = sqlite3_column_bytes(stmt, 2);
|
||||
const void * lease_clientid = sqlite3_column_blob(stmt, 3);
|
||||
uint32_t lease_clientid_len = sqlite3_column_bytes(stmt, 3);
|
||||
uint32_t lease_valid_lft = sqlite3_column_int(stmt, 4);
|
||||
|
||||
// cltt
|
||||
const unsigned char *lease_cltt = sqlite3_column_text(stmt, 5);
|
||||
|
||||
uint32_t lease_pool_id = sqlite3_column_int(stmt, 6);
|
||||
uint32_t lease_fixed = sqlite3_column_int(stmt, 7);
|
||||
|
||||
const unsigned char *lease_hostname = sqlite3_column_text(stmt, 8);
|
||||
|
||||
uint32_t lease_fqdn_fwd = sqlite3_column_int(stmt, 9);
|
||||
uint32_t lease_fqdn_rev = sqlite3_column_int(stmt, 10);
|
||||
|
||||
if (lease_addr || lease_hwaddr || lease_hwaddr_len || lease_clientid ||
|
||||
lease_clientid_len || lease_valid_lft || lease_cltt || lease_pool_id ||
|
||||
lease_fixed || lease_hostname || lease_fqdn_fwd || lease_fqdn_rev) {
|
||||
// we don't need this information, we just want to obtain it to measure
|
||||
// the overhead. That strange if is only to quell compiler/cppcheck
|
||||
// warning about unused variables.
|
||||
|
||||
cnt = 1;
|
||||
}
|
||||
|
||||
cnt = 1; // there is at least one row
|
||||
break;
|
||||
}
|
||||
case SQLITE_DONE:
|
||||
cnt = 0; // there are no rows at all (i.e. no such lease)
|
||||
break;
|
||||
default:
|
||||
failure("Failed to execute SELECT clause");
|
||||
}
|
||||
|
||||
// let's reset the compiled statement, so it can be used in the
|
||||
// next iteration
|
||||
result = sqlite3_reset(stmt);
|
||||
if (result != SQLITE_OK) {
|
||||
failure("Failed to execute sqlite3_reset()");
|
||||
}
|
||||
}
|
||||
|
||||
if (verbose_) {
|
||||
cout << (cnt?".":"X");
|
||||
}
|
||||
}
|
||||
|
||||
if (compiled_stmt_) {
|
||||
int result = sqlite3_finalize(stmt);
|
||||
if (result != SQLITE_OK) {
|
||||
failure("sqlite3_finalize() failed");
|
||||
}
|
||||
}
|
||||
|
||||
cout << endl;
|
||||
}
|
||||
|
||||
void SQLite_uBenchmark::updateLease4Test() {
|
||||
if (!db_) {
|
||||
throw "SQLite connection is closed.";
|
||||
}
|
||||
|
||||
cout << "UPDATE: ";
|
||||
|
||||
sqlite3_stmt *stmt = NULL;
|
||||
if (compiled_stmt_) {
|
||||
const char query[] = "UPDATE lease4 SET valid_lft=1002, cltt='now' WHERE addr=?1";
|
||||
|
||||
int result = sqlite3_prepare_v2(db_, query, strlen(query), &stmt, NULL);
|
||||
if (result != SQLITE_OK) {
|
||||
failure("Failed to compile statement");
|
||||
}
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < num_; i++) {
|
||||
|
||||
uint32_t addr = BASE_ADDR4 + random() % num_;
|
||||
|
||||
if (!compiled_stmt_) {
|
||||
char* errorMsg = NULL;
|
||||
char query[512];
|
||||
sprintf(query, "UPDATE lease4 SET valid_lft=1002, cltt='now' WHERE addr=%d",
|
||||
addr);
|
||||
|
||||
int result = sqlite3_exec(db_, query, NULL /* no callback here*/, 0, &errorMsg);
|
||||
if (result != SQLITE_OK) {
|
||||
stringstream tmp;
|
||||
tmp << "UPDATE error:" << errorMsg;
|
||||
failure(tmp.str().c_str());
|
||||
}
|
||||
} else {
|
||||
|
||||
int result = sqlite3_bind_int(stmt, 1, addr);
|
||||
if (result != SQLITE_OK) {
|
||||
failure("sqlite3_bind_int() for column 1");
|
||||
}
|
||||
|
||||
result = sqlite3_step(stmt);
|
||||
if (result != SQLITE_OK && result != SQLITE_DONE) {
|
||||
failure("Failed to execute sqlite3_step() for UPDATE");
|
||||
}
|
||||
|
||||
// let's reset the compiled statement, so it can be used in the
|
||||
// next iteration
|
||||
result = sqlite3_reset(stmt);
|
||||
if (result != SQLITE_OK) {
|
||||
failure("Failed to execute sqlite3_reset()");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (verbose_) {
|
||||
cout << ".";
|
||||
}
|
||||
}
|
||||
|
||||
if (compiled_stmt_) {
|
||||
int result = sqlite3_finalize(stmt);
|
||||
if (result != SQLITE_OK) {
|
||||
failure("sqlite3_finalize() failed");
|
||||
}
|
||||
}
|
||||
|
||||
cout << endl;
|
||||
}
|
||||
|
||||
void SQLite_uBenchmark::deleteLease4Test() {
|
||||
if (!db_) {
|
||||
throw "SQLite connection is closed.";
|
||||
}
|
||||
|
||||
cout << "DELETE: ";
|
||||
|
||||
sqlite3_stmt *stmt = NULL;
|
||||
if (compiled_stmt_) {
|
||||
const char query[] = "DELETE FROM lease4 WHERE addr=?1";
|
||||
|
||||
int result = sqlite3_prepare_v2(db_, query, strlen(query), &stmt, NULL);
|
||||
if (result != SQLITE_OK) {
|
||||
failure("Failed to compile statement");
|
||||
}
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < num_; i++) {
|
||||
|
||||
uint32_t addr = BASE_ADDR4 + i;
|
||||
if (!compiled_stmt_) {
|
||||
char* errorMsg = NULL;
|
||||
|
||||
char query[2000];
|
||||
sprintf(query, "DELETE FROM lease4 WHERE addr=%d", addr);
|
||||
int result = sqlite3_exec(db_, query, NULL /* no callback here*/, 0, &errorMsg);
|
||||
if (result != SQLITE_OK) {
|
||||
stringstream tmp;
|
||||
tmp << "DELETE error:" << errorMsg;
|
||||
failure(tmp.str().c_str());
|
||||
}
|
||||
} else {
|
||||
// compiled statement
|
||||
|
||||
int result = sqlite3_bind_int(stmt, 1, addr);
|
||||
if (result != SQLITE_OK) {
|
||||
failure("sqlite3_bind_int() for column 1");
|
||||
}
|
||||
|
||||
result = sqlite3_step(stmt);
|
||||
if (result != SQLITE_OK && result != SQLITE_DONE) {
|
||||
failure("Failed to execute sqlite3_step() for UPDATE");
|
||||
}
|
||||
|
||||
// let's reset the compiled statement, so it can be used in the
|
||||
// next iteration
|
||||
result = sqlite3_reset(stmt);
|
||||
if (result != SQLITE_OK) {
|
||||
failure("Failed to execute sqlite3_reset()");
|
||||
}
|
||||
|
||||
}
|
||||
if (verbose_) {
|
||||
cout << ".";
|
||||
}
|
||||
}
|
||||
|
||||
if (compiled_stmt_) {
|
||||
int result = sqlite3_finalize(stmt);
|
||||
if (result != SQLITE_OK) {
|
||||
failure("sqlite3_finalize() failed");
|
||||
}
|
||||
}
|
||||
|
||||
cout << endl;
|
||||
}
|
||||
|
||||
void SQLite_uBenchmark::printInfo() {
|
||||
cout << "SQLite version is " << sqlite3_libversion()
|
||||
<< "sourceid version is " << sqlite3_sourceid() << endl;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int main(int argc, char* const argv[]) {
|
||||
|
||||
const char* filename = "sqlite.db";
|
||||
uint32_t num = 100;
|
||||
bool sync = true;
|
||||
bool verbose = true;
|
||||
|
||||
SQLite_uBenchmark bench(filename, num, sync, verbose);
|
||||
|
||||
bench.parseCmdline(argc, argv);
|
||||
|
||||
int result = bench.run();
|
||||
|
||||
return (result);
|
||||
}
|
@ -1,74 +0,0 @@
|
||||
// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
#include <string>
|
||||
#include "benchmark.h"
|
||||
|
||||
/// @brief SQLite benchmark
|
||||
///
|
||||
/// That is a specific backend implementation. See \ref uBenchmark class for
|
||||
/// detailed explanation of its operations. This class uses SQLite as DB backend.
|
||||
class SQLite_uBenchmark: public uBenchmark {
|
||||
public:
|
||||
|
||||
/// @brief The sole SQL benchmark constructor
|
||||
///
|
||||
/// DB file must be present and appropriate database schema must
|
||||
/// be used. See sqlite.schema script and isc-dhcp-perf-guide.html
|
||||
/// for details.
|
||||
///
|
||||
/// sync flag affects "PRAGMA synchronous" to be ON or OFF.
|
||||
///
|
||||
/// @param filename name of the SQLite DB file. Must be present.
|
||||
/// @param num_iterations number of iterations of basic lease operations
|
||||
/// @param sync should the operations be synchronous or not?
|
||||
/// @param verbose would you like extra details be logged?
|
||||
SQLite_uBenchmark(const std::string& filename,
|
||||
uint32_t num_iterations,
|
||||
bool sync, bool verbose);
|
||||
|
||||
/// @brief Prints SQLite version info.
|
||||
virtual void printInfo();
|
||||
|
||||
/// @brief Opens connection to the SQLite database.
|
||||
virtual void connect();
|
||||
|
||||
/// @brief Closes connection to the SQLite database.
|
||||
virtual void disconnect();
|
||||
|
||||
/// @brief Creates new leases.
|
||||
///
|
||||
/// See uBenchmark::createLease4Test() for detailed explanation.
|
||||
virtual void createLease4Test();
|
||||
|
||||
/// @brief Searches for existing leases.
|
||||
///
|
||||
/// See uBenchmark::searchLease4Test() for detailed explanation.
|
||||
virtual void searchLease4Test();
|
||||
|
||||
/// @brief Updates existing leases.
|
||||
///
|
||||
/// See uBenchmark::updateLease4Test() for detailed explanation.
|
||||
virtual void updateLease4Test();
|
||||
|
||||
/// @brief Deletes existing leases.
|
||||
///
|
||||
/// See uBenchmark::deleteLease4Test() for detailed explanation.
|
||||
virtual void deleteLease4Test();
|
||||
|
||||
protected:
|
||||
|
||||
/// Handle to SQLite database connection.
|
||||
sqlite3 *db_;
|
||||
};
|
Loading…
x
Reference in New Issue
Block a user