mirror of https://github.com/sysown/proxysql
Conflicts: include/MySQL_Protocol.h include/mysql_connection.h lib/Makefile lib/MySQL_Session.cpppull/739/head
commit
febd61bc9e
@ -0,0 +1,116 @@
|
||||
#ifndef CLASS_MYSQL_PREPARED_STATEMENT_H
|
||||
#define CLASS_MYSQL_PREPARED_STATEMENT_H
|
||||
|
||||
#include "proxysql.h"
|
||||
#include "cpp.h"
|
||||
|
||||
/*
|
||||
One of the main challenge in handling prepared statement (PS) is that a single
|
||||
PS could be executed on multiple backends, and on each backend it could have a
|
||||
different stmt_id.
|
||||
For this reason ProxySQL returns to the client a stmt_id generated by the proxy
|
||||
itself, and internally maps client's stmt_id with the backend stmt_id.
|
||||
|
||||
The implementation in ProxySQL is, simplified, the follow:
|
||||
* when a client sends a MYSQL_COM_STMT_PREPARE, ProxySQL executes it to one of
|
||||
the backend
|
||||
* the backend returns a stmt_id. This stmt_id is NOT returned to the client. The
|
||||
stmt_id returned from the backend is stored in MySQL_STMTs_local(), and
|
||||
MySQL_STMTs_local() is responsible for mapping the connection's MYSQL_STMT
|
||||
and a global_stmt_id
|
||||
* the global_stmt_id is the stmt_id returned to the client
|
||||
* the global_stmt_id is used to locate the relevant MySQL_STMT_Global_info() in
|
||||
MySQL_STMT_Manager()
|
||||
* MySQL_STMT_Global_info() stores all metadata associated with a PS
|
||||
* MySQL_STMT_Manager() is responsible for storing all MySQL_STMT_Global_info()
|
||||
in global structures accessible and shareble by all threads.
|
||||
|
||||
To summarie the most important classes:
|
||||
* MySQL_STMT_Global_info() stores all metadata associated with a PS
|
||||
* MySQL_STMT_Manager() stores all the MySQL_STMT_Global_info(), indexes using
|
||||
a global_stmt_id that iis the stmt_id generated by ProxySQL and returned to
|
||||
the client
|
||||
* MySQL_STMTs_local() associate PS located in a backend connection to a
|
||||
global_stmt_id
|
||||
*/
|
||||
|
||||
|
||||
// class MySQL_STMTs_local associates a global statement ID with a local statement ID for a specific connection
|
||||
class MySQL_STMTs_local {
|
||||
private:
|
||||
unsigned int num_entries;
|
||||
std::map<uint32_t, MYSQL_STMT *> m;
|
||||
public:
|
||||
MySQL_STMTs_local() {
|
||||
num_entries=0;
|
||||
}
|
||||
~MySQL_STMTs_local();
|
||||
// we declare it here to be inline
|
||||
void insert(uint32_t global_statement_id, MYSQL_STMT *stmt) {
|
||||
std::pair<std::map<uint32_t, MYSQL_STMT *>::iterator,bool> ret;
|
||||
ret=m.insert(std::make_pair(global_statement_id, stmt));
|
||||
if (ret.second==true) {
|
||||
num_entries++;
|
||||
}
|
||||
}
|
||||
// we declare it here to be inline
|
||||
MYSQL_STMT * find(uint32_t global_statement_id) {
|
||||
auto s=m.find(global_statement_id);
|
||||
if (s!=m.end()) { // found
|
||||
return s->second;
|
||||
}
|
||||
return NULL; // not found
|
||||
}
|
||||
bool erase(uint32_t global_statement_id);
|
||||
uint64_t compute_hash(unsigned int hostgroup, char *user, char *schema, char *query, unsigned int query_length);
|
||||
};
|
||||
|
||||
|
||||
|
||||
// class MySQL_STMT_Global_info represents information about a MySQL Prepared Statement
|
||||
// it is an internal representation of prepared statement
|
||||
// it include all metadata associated with it
|
||||
class MySQL_STMT_Global_info {
|
||||
private:
|
||||
void compute_hash();
|
||||
public:
|
||||
uint64_t hash;
|
||||
char *username;
|
||||
char *schemaname;
|
||||
char *query;
|
||||
unsigned int query_length;
|
||||
unsigned int hostgroup_id;
|
||||
int ref_count;
|
||||
uint32_t statement_id;
|
||||
uint16_t num_columns;
|
||||
uint16_t num_params;
|
||||
uint16_t warning_count;
|
||||
MYSQL_FIELD **fields;
|
||||
struct {
|
||||
int cache_ttl;
|
||||
int timeout;
|
||||
int delay;
|
||||
} properties;
|
||||
//MYSQL_BIND **params; // seems unused
|
||||
MySQL_STMT_Global_info(uint32_t id, unsigned int h, char *u, char *s, char *q, unsigned int ql, MYSQL_STMT *stmt, uint64_t _h);
|
||||
~MySQL_STMT_Global_info();
|
||||
};
|
||||
|
||||
class MySQL_STMT_Manager {
|
||||
private:
|
||||
uint32_t next_statement_id;
|
||||
rwlock_t rwlock;
|
||||
std::map<uint32_t, MySQL_STMT_Global_info *> m; // map using statement id
|
||||
std::map<uint64_t, MySQL_STMT_Global_info *> h; // map using hashes
|
||||
public:
|
||||
MySQL_STMT_Manager();
|
||||
~MySQL_STMT_Manager();
|
||||
int ref_count(uint32_t statement_id, int cnt, bool lock=true);
|
||||
MySQL_STMT_Global_info * add_prepared_statement(unsigned int h, char *u, char *s, char *q, unsigned int ql, MYSQL_STMT *stmt, bool lock=true);
|
||||
MySQL_STMT_Global_info * add_prepared_statement(unsigned int h, char *u, char *s, char *q, unsigned int ql, MYSQL_STMT *stmt, int _cache_ttl, int _timeout, int _delay, bool lock=true);
|
||||
MySQL_STMT_Global_info * find_prepared_statement_by_stmt_id(uint32_t id, bool lock=true);
|
||||
MySQL_STMT_Global_info * find_prepared_statement_by_hash(uint64_t hash, bool lock=true);
|
||||
uint32_t total_prepared_statements() { return next_statement_id-1; }
|
||||
};
|
||||
|
||||
#endif /* CLASS_MYSQL_PREPARED_STATEMENT_H */
|
||||
@ -0,0 +1,281 @@
|
||||
#include "proxysql.h"
|
||||
#include "cpp.h"
|
||||
|
||||
#include "SpookyV2.h"
|
||||
|
||||
extern MySQL_STMT_Manager *GloMyStmt;
|
||||
|
||||
|
||||
|
||||
|
||||
static uint64_t stmt_compute_hash(unsigned int hostgroup, char *user, char *schema, char *query, unsigned int query_length) {
|
||||
int l=0;
|
||||
l+=sizeof(hostgroup);
|
||||
l+=strlen(user);
|
||||
l+=strlen(schema);
|
||||
// two random seperators
|
||||
#define _COMPUTE_HASH_DEL1_ "-ujhtgf76y576574fhYTRDFwdt-"
|
||||
#define _COMPUTE_HASH_DEL2_ "-8k7jrhtrgJHRgrefgreRFewg6-"
|
||||
l+=strlen(_COMPUTE_HASH_DEL1_);
|
||||
l+=strlen(_COMPUTE_HASH_DEL2_);
|
||||
l+=query_length;
|
||||
char *buf=(char *)malloc(l);
|
||||
l=0;
|
||||
// write hostgroup
|
||||
memcpy(buf,&hostgroup,sizeof(hostgroup));
|
||||
l+=sizeof(hostgroup);
|
||||
|
||||
// write user
|
||||
strcpy(buf+l,user);
|
||||
l+=strlen(user);
|
||||
|
||||
// write delimiter1
|
||||
strcpy(buf+l,_COMPUTE_HASH_DEL1_);
|
||||
l+=strlen(_COMPUTE_HASH_DEL1_);
|
||||
|
||||
// write schema
|
||||
strcpy(buf+l,schema);
|
||||
l+=strlen(schema);
|
||||
|
||||
// write delimiter2
|
||||
strcpy(buf+l,_COMPUTE_HASH_DEL2_);
|
||||
l+=strlen(_COMPUTE_HASH_DEL2_);
|
||||
|
||||
// write query
|
||||
memcpy(buf+l,query,query_length);
|
||||
l+=query_length;
|
||||
|
||||
uint64_t hash=SpookyHash::Hash64(buf,l,0);
|
||||
free(buf);
|
||||
return hash;
|
||||
}
|
||||
|
||||
|
||||
void MySQL_STMT_Global_info::compute_hash() {
|
||||
hash=stmt_compute_hash(hostgroup_id, username, schemaname, query, query_length);
|
||||
}
|
||||
|
||||
uint64_t MySQL_STMTs_local::compute_hash(unsigned int hostgroup, char *user, char *schema, char *query, unsigned int query_length){
|
||||
uint64_t hash;
|
||||
hash=stmt_compute_hash(hostgroup, user, schema, query, query_length);
|
||||
return hash;
|
||||
}
|
||||
|
||||
MySQL_STMTs_local::~MySQL_STMTs_local() {
|
||||
// Note: we do not free the prepared statements because we assume that
|
||||
// if we call this destructor the connection is being destroyed anyway
|
||||
for (std::map<uint32_t, MYSQL_STMT *>::iterator it=m.begin(); it!=m.end(); ++it) {
|
||||
uint32_t stmt_id=it->first;
|
||||
GloMyStmt->ref_count(stmt_id,-1);
|
||||
}
|
||||
m.erase(m.begin(),m.end());
|
||||
}
|
||||
|
||||
bool MySQL_STMTs_local::erase(uint32_t global_statement_id) {
|
||||
auto s=m.find(global_statement_id);
|
||||
if (s!=m.end()) { // found
|
||||
if (num_entries>1000) {
|
||||
MYSQL_STMT *stmt=s->second;
|
||||
mysql_stmt_close(stmt);
|
||||
m.erase(s);
|
||||
num_entries--;
|
||||
return true; // we truly removed the prepared statement
|
||||
}
|
||||
}
|
||||
return false; // we don't really remove the prepared statement
|
||||
}
|
||||
|
||||
MySQL_STMT_Manager::MySQL_STMT_Manager() {
|
||||
spinlock_rwlock_init(&rwlock);
|
||||
next_statement_id=1; // we initialize this as 1 because we 0 is not allowed
|
||||
}
|
||||
|
||||
MySQL_STMT_Manager::~MySQL_STMT_Manager() {
|
||||
for (std::map<uint32_t, MySQL_STMT_Global_info *>::iterator it=m.begin(); it!=m.end(); ++it) {
|
||||
MySQL_STMT_Global_info *a=it->second;
|
||||
delete a;
|
||||
}
|
||||
m.erase(m.begin(),m.end());
|
||||
// we do not loop in h because all the MySQL_STMT_Global_info() were already deleted
|
||||
h.erase(h.begin(),h.end());
|
||||
}
|
||||
|
||||
int MySQL_STMT_Manager::ref_count(uint32_t statement_id, int cnt, bool lock) {
|
||||
int ret=-1;
|
||||
if (lock) {
|
||||
spin_wrlock(&rwlock);
|
||||
}
|
||||
auto s = m.find(statement_id);
|
||||
if (s!=m.end()) {
|
||||
MySQL_STMT_Global_info *a=s->second;
|
||||
a->ref_count+=cnt;
|
||||
ret=a->ref_count;
|
||||
}
|
||||
if (lock) {
|
||||
spin_wrunlock(&rwlock);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
MySQL_STMT_Global_info * MySQL_STMT_Manager::add_prepared_statement(unsigned int _h, char *u, char *s, char *q, unsigned int ql, MYSQL_STMT *stmt, bool lock) {
|
||||
return add_prepared_statement(_h, u, s, q, ql, stmt, -1, -1, -1, lock);
|
||||
}
|
||||
|
||||
MySQL_STMT_Global_info * MySQL_STMT_Manager::add_prepared_statement(unsigned int _h, char *u, char *s, char *q, unsigned int ql, MYSQL_STMT *stmt, int _cache_ttl, int _timeout, int _delay, bool lock) {
|
||||
MySQL_STMT_Global_info *ret=NULL;
|
||||
uint64_t hash=stmt_compute_hash(_h, u, s, q, ql); // this identifies the prepared statement
|
||||
if (lock) {
|
||||
spin_wrlock(&rwlock);
|
||||
}
|
||||
// try to find the statement
|
||||
auto f = h.find(hash);
|
||||
if (f!=h.end()) {
|
||||
// found it!
|
||||
//MySQL_STMT_Global_info *a=f->second;
|
||||
//ret=a->statement_id;
|
||||
ret=f->second;
|
||||
} else {
|
||||
// we need to create a new one
|
||||
MySQL_STMT_Global_info *a=new MySQL_STMT_Global_info(next_statement_id,_h,u,s,q,ql,stmt,hash);
|
||||
a->properties.cache_ttl=_cache_ttl;
|
||||
a->properties.timeout=_timeout;
|
||||
a->properties.delay=_delay;
|
||||
// insert it in both maps
|
||||
m.insert(std::make_pair(a->statement_id, a));
|
||||
h.insert(std::make_pair(a->hash, a));
|
||||
//ret=a->statement_id;
|
||||
ret=a;
|
||||
next_statement_id++; // increment it
|
||||
}
|
||||
|
||||
if (lock) {
|
||||
spin_wrunlock(&rwlock);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
MySQL_STMT_Global_info * MySQL_STMT_Manager::find_prepared_statement_by_stmt_id(uint32_t id, bool lock) {
|
||||
MySQL_STMT_Global_info *ret=NULL; // assume we do not find it
|
||||
if (lock) {
|
||||
spin_wrlock(&rwlock);
|
||||
}
|
||||
|
||||
auto s=m.find(id);
|
||||
if (s!=m.end()) {
|
||||
ret=s->second;
|
||||
}
|
||||
|
||||
if (lock) {
|
||||
spin_wrunlock(&rwlock);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
MySQL_STMT_Global_info * MySQL_STMT_Manager::find_prepared_statement_by_hash(uint64_t hash, bool lock) {
|
||||
MySQL_STMT_Global_info *ret=NULL; // assume we do not find it
|
||||
if (lock) {
|
||||
spin_wrlock(&rwlock);
|
||||
}
|
||||
|
||||
auto s=h.find(hash);
|
||||
if (s!=h.end()) {
|
||||
ret=s->second;
|
||||
}
|
||||
|
||||
if (lock) {
|
||||
spin_wrunlock(&rwlock);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
MySQL_STMT_Global_info::MySQL_STMT_Global_info(uint32_t id, unsigned int h, char *u, char *s, char *q, unsigned int ql, MYSQL_STMT *stmt, uint64_t _h) {
|
||||
statement_id=id;
|
||||
hostgroup_id=h;
|
||||
ref_count=0;
|
||||
username=strdup(u);
|
||||
schemaname=strdup(s);
|
||||
query=(char *)malloc(ql);
|
||||
memcpy(query,q,ql);
|
||||
query_length=ql;
|
||||
num_params=stmt->param_count;
|
||||
num_columns=stmt->field_count;
|
||||
warning_count=stmt->upsert_status.warning_count;
|
||||
if (_h) {
|
||||
hash=_h;
|
||||
} else {
|
||||
compute_hash();
|
||||
}
|
||||
|
||||
// set default properties:
|
||||
properties.cache_ttl=-1;
|
||||
properties.timeout=-1;
|
||||
properties.delay=-1;
|
||||
|
||||
fields=NULL;
|
||||
if (num_columns) {
|
||||
fields=(MYSQL_FIELD **)malloc(num_columns*sizeof(MYSQL_FIELD *));
|
||||
uint16_t i;
|
||||
for (i=0;i<num_columns;i++) {
|
||||
fields[i]=(MYSQL_FIELD *)malloc(sizeof(MYSQL_FIELD));
|
||||
MYSQL_FIELD *fs=&(stmt->fields[i]);
|
||||
MYSQL_FIELD *fd=fields[i];
|
||||
// first copy all fields
|
||||
memcpy(fd,fs,sizeof(MYSQL_FIELD));
|
||||
// then duplicate strings
|
||||
fd->name = ( fs->name ? strdup(fs->name) : NULL );
|
||||
fd->org_name = ( fs->org_name ? strdup(fs->org_name) : NULL );
|
||||
fd->table = ( fs->table ? strdup(fs->table) : NULL );
|
||||
fd->org_table = ( fs->org_table ? strdup(fs->org_table) : NULL );
|
||||
fd->db = ( fs->db ? strdup(fs->db) : NULL );
|
||||
fd->catalog = ( fs->catalog ? strdup(fs->catalog) : NULL );
|
||||
fd->def = ( fs->def ? strdup(fs->def) : NULL );
|
||||
}
|
||||
}
|
||||
/*
|
||||
params=NULL;
|
||||
if(num_params) {
|
||||
params=(MYSQL_BIND **)malloc(num_columns*sizeof(MYSQL_BIND *));
|
||||
uint16_t i;
|
||||
for (i=0;i<num_params;i++) {
|
||||
params[i]=(MYSQL_BIND *)malloc(sizeof(MYSQL_BIND));
|
||||
MYSQL_BIND *ps=&(stmt->params[i]);
|
||||
MYSQL_BIND *pd=params[i];
|
||||
// copy all params
|
||||
memcpy(pd,ps,sizeof(MYSQL_BIND));
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
MySQL_STMT_Global_info::~MySQL_STMT_Global_info() {
|
||||
free(username);
|
||||
free(schemaname);
|
||||
free(query);
|
||||
if (num_columns) {
|
||||
uint16_t i;
|
||||
for (i=0;i<num_columns;i++) {
|
||||
MYSQL_FIELD *f=fields[i];
|
||||
if (f->name) { free(f->name); f->name=NULL; }
|
||||
if (f->org_name) { free(f->org_name); f->org_name=NULL; }
|
||||
if (f->table) { free(f->table); f->table=NULL; }
|
||||
if (f->org_table) { free(f->org_table); f->org_table=NULL; }
|
||||
if (f->db) { free(f->db); f->db=NULL; }
|
||||
if (f->catalog) { free(f->catalog); f->catalog=NULL; }
|
||||
if (f->def) { free(f->def); f->def=NULL; }
|
||||
free(fields[i]);
|
||||
}
|
||||
free(fields);
|
||||
fields=NULL;
|
||||
}
|
||||
/*
|
||||
if (num_params) {
|
||||
uint16_t i;
|
||||
for (i=0;i<num_params;i++) {
|
||||
free(params[i]);
|
||||
}
|
||||
free(params);
|
||||
params=NULL;
|
||||
}
|
||||
*/
|
||||
}
|
||||
@ -0,0 +1,7 @@
|
||||
client1
|
||||
client2
|
||||
client3
|
||||
client4
|
||||
client5
|
||||
client6
|
||||
client7
|
||||
@ -0,0 +1,85 @@
|
||||
|
||||
|
||||
|
||||
|
||||
DEPS_PATH=../../deps
|
||||
|
||||
MARIADB_PATH=$(DEPS_PATH)/mariadb-client-library/mariadb_client
|
||||
MARIADB_IDIR=$(MARIADB_PATH)/include
|
||||
MARIADB_LDIR=$(MARIADB_PATH)/libmariadb
|
||||
|
||||
|
||||
DAEMONPATH=$(DEPS_PATH)/libdaemon/libdaemon
|
||||
DAEMONPATH_IDIR=$(DAEMONPATH)
|
||||
DAEMONPATH_LDIR=$(DAEMONPATH)/libdaemon/.libs
|
||||
|
||||
JEMALLOC_PATH=$(DEPS_PATH)/jemalloc/jemalloc
|
||||
JEMALLOC_IDIR=$(JEMALLOC_PATH)/include/jemalloc
|
||||
JEMALLOC_LDIR=$(JEMALLOC_PATH)/lib
|
||||
|
||||
LIBCONFIG_PATH=$(DEPS_PATH)/libconfig/libconfig-1.4.9
|
||||
LIBCONFIG_IDIR=-I$(LIBCONFIG_PATH)/lib
|
||||
LIBCONFIG_LDIR=-L$(LIBCONFIG_PATH)/lib/.libs
|
||||
|
||||
LIBEVENT_PATH=$(DEPS_PATH)/libevent/libevent
|
||||
LIBEVENT_IDIR=$(LIBEVENT_PATH)/include
|
||||
LIBEVENT_LDIR=$(LIBEVENT_PATH)/.libs
|
||||
|
||||
RE2_PATH=$(DEPS_PATH)/re2/re2
|
||||
RE2_IDIR=$(RE2_PATH)
|
||||
|
||||
SQLITE3_DIR=$(DEPS_PATH)/sqlite3/sqlite3
|
||||
|
||||
IDIR=../../include
|
||||
LDIR=../../lib
|
||||
IDIRS=-I$(IDIR) -I$(JEMALLOC_IDIR) -I$(MARIADB_IDIR) $(LIBCONFIG_IDIR) -I$(DAEMONPATH_IDIR) -I$(SQLITE3_DIR)
|
||||
LDIRS=-L$(LDIR) -L$(JEMALLOC_LDIR) $(LIBCONFIG_LDIR) -L$(RE2_PATH)/obj -L$(LIBEVENT_LDIR) -L$(MARIADB_LDIR) -L$(DAEMONPATH_LDIR)
|
||||
|
||||
DEBUG=-DDEBUG
|
||||
MYCPPFLAGS=-std=c++11 $(IDIRS) $(OPTZ) $(DEBUG) -ggdb
|
||||
LDFLAGS+=
|
||||
MYLIBS=-Wl,--export-dynamic -Wl,-Bstatic -lconfig -lproxysql -ldaemon -ljemalloc -lconfig++ -lre2 -levent -lmariadbclient -Wl,-Bdynamic -lpthread -lm -lz -lrt -lcrypto -lssl $(EXTRALINK)
|
||||
|
||||
UNAME_S := $(shell uname -s)
|
||||
ifeq ($(UNAME_S),Linux)
|
||||
MYLIBS+= -ldl
|
||||
endif
|
||||
ifeq ($(UNAME_S),FreeBSD)
|
||||
MYLIBS+= -lexecinfo
|
||||
endif
|
||||
|
||||
LIBPROXYSQLAR=$(LDIR)/libproxysql.a
|
||||
|
||||
.PHONY: default
|
||||
default: client1
|
||||
|
||||
client1: client1.cpp
|
||||
$(CXX) -o $@ $@.cpp $(LIBPROXYSQLAR) $(MYCPPFLAGS) $(CPPFLAGS) $(LDIRS) $(LIBS) $(LDFLAGS) $(MYLIBS)
|
||||
|
||||
client2: client2.cpp
|
||||
$(CXX) -o $@ $@.cpp $(LIBPROXYSQLAR) $(MYCPPFLAGS) $(CPPFLAGS) $(LDIRS) $(LIBS) $(LDFLAGS) $(MYLIBS)
|
||||
|
||||
client3: client3.cpp
|
||||
$(CXX) -o $@ $@.cpp $(LIBPROXYSQLAR) $(MYCPPFLAGS) $(CPPFLAGS) $(LDIRS) $(LIBS) $(LDFLAGS) $(MYLIBS)
|
||||
|
||||
client4: client4.cpp
|
||||
$(CXX) -o $@ $@.cpp $(LIBPROXYSQLAR) $(MYCPPFLAGS) $(CPPFLAGS) $(LDIRS) $(LIBS) $(LDFLAGS) $(MYLIBS)
|
||||
|
||||
client5: client5.cpp
|
||||
$(CXX) -o $@ $@.cpp $(LIBPROXYSQLAR) $(MYCPPFLAGS) $(CPPFLAGS) $(LDIRS) $(LIBS) $(LDFLAGS) $(MYLIBS)
|
||||
|
||||
client6: client6.cpp
|
||||
$(CXX) -o $@ $@.cpp $(LIBPROXYSQLAR) $(MYCPPFLAGS) $(CPPFLAGS) $(LDIRS) $(LIBS) $(LDFLAGS) $(MYLIBS)
|
||||
|
||||
client7: client7.cpp
|
||||
$(CXX) -o $@ $@.cpp $(LIBPROXYSQLAR) $(MYCPPFLAGS) $(CPPFLAGS) $(LDIRS) $(LIBS) $(LDFLAGS) $(MYLIBS)
|
||||
|
||||
client8: client8.cpp
|
||||
$(CXX) -o $@ $@.cpp $(LIBPROXYSQLAR) $(MYCPPFLAGS) $(CPPFLAGS) $(LDIRS) $(LIBS) $(LDFLAGS) $(MYLIBS)
|
||||
|
||||
|
||||
default: $(EXECUTABLE)
|
||||
|
||||
clean:
|
||||
rm -f *~ core $(default)
|
||||
|
||||
@ -0,0 +1,75 @@
|
||||
#include "proxysql.h"
|
||||
#include "cpp.h"
|
||||
|
||||
#define QUERY1 "SELECT ? + ? + ?"
|
||||
MYSQL *mysql;
|
||||
MYSQL_STMT *stmt;
|
||||
uint32_t statement_id;
|
||||
uint16_t num_params;
|
||||
uint16_t num_columns;
|
||||
uint16_t warning_count;
|
||||
|
||||
int run_stmt(MYSQL_STMT *stmt, int int_data) {
|
||||
MYSQL_BIND bind[3];
|
||||
MYSQL_RES *prepare_meta_result;
|
||||
bind[0].buffer_type= MYSQL_TYPE_LONG;
|
||||
bind[0].buffer= (char *)&int_data;
|
||||
bind[0].is_null= 0;
|
||||
bind[0].length= 0;
|
||||
bind[1].buffer_type= MYSQL_TYPE_LONG;
|
||||
bind[1].buffer= (char *)&int_data;
|
||||
bind[1].is_null= 0;
|
||||
bind[1].length= 0;
|
||||
bind[2].buffer_type= MYSQL_TYPE_LONG;
|
||||
bind[2].buffer= (char *)&int_data;
|
||||
bind[2].is_null= 0;
|
||||
bind[2].length= 0;
|
||||
if (mysql_stmt_bind_param(stmt, bind)) {
|
||||
fprintf(stderr, " mysql_stmt_bind_param() failed\n");
|
||||
fprintf(stderr, " %s\n", mysql_stmt_error(stmt));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
prepare_meta_result = mysql_stmt_result_metadata(stmt); // FIXME: no error check
|
||||
if (mysql_stmt_execute(stmt)) {
|
||||
fprintf(stderr, " mysql_stmt_execute(), 1 failed\n");
|
||||
fprintf(stderr, " %s\n", mysql_stmt_error(stmt));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
// memset(bind, 0, sizeof(bind));
|
||||
if (mysql_stmt_store_result(stmt)) {
|
||||
fprintf(stderr, " mysql_stmt_store_result() failed\n");
|
||||
fprintf(stderr, " %s\n", mysql_stmt_error(stmt));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
mysql_free_result(prepare_meta_result);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int main() {
|
||||
std::mt19937 mt_rand(time(0));
|
||||
mysql = mysql_init(NULL);
|
||||
if (!mysql_real_connect(mysql,"127.0.0.1","msandbox","msandbox","test",6033,NULL,0)) {
|
||||
//if (!mysql_real_connect(mysql,"127.0.0.1","root","","test",3306,NULL,0)) {
|
||||
fprintf(stderr, "Failed to connect to database: Error: %s\n", mysql_error(mysql));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
stmt = mysql_stmt_init(mysql);
|
||||
if (!stmt) {
|
||||
fprintf(stderr, " mysql_stmt_init(), out of memory\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (mysql_stmt_prepare(stmt, QUERY1, strlen(QUERY1))) {
|
||||
fprintf(stderr, " mysql_stmt_prepare(), failed: %d, %s\n" , mysql_errno(mysql), mysql_stmt_error(stmt));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
// param_count= mysql_stmt_param_count(stmt);
|
||||
// fprintf(stdout, " total parameters in Query1 : %d\n", param_count);
|
||||
statement_id=stmt->stmt_id;
|
||||
num_params=stmt->param_count;
|
||||
num_columns=stmt->field_count;
|
||||
warning_count=stmt->upsert_status.warning_count;
|
||||
fprintf(stdout, "statement_id=%d , columns=%d , params=%d , warnings=%d\n", statement_id, num_columns, num_params, warning_count);
|
||||
run_stmt(stmt,(uint32_t)mt_rand());
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1,178 @@
|
||||
#include "proxysql.h"
|
||||
#include "cpp.h"
|
||||
|
||||
#include <ctime>
|
||||
|
||||
#define QUERY1 "SELECT ?"
|
||||
#define NUMPREP 100000
|
||||
#define NUMPRO 1000
|
||||
//#define NUMPREP 160
|
||||
//#define NUMPRO 4
|
||||
#define LOOPS 10
|
||||
#define USER "root"
|
||||
#define SCHEMA "test"
|
||||
MYSQL *mysql;
|
||||
MYSQL_STMT **stmt;
|
||||
uint32_t statement_id;
|
||||
uint16_t num_params;
|
||||
uint16_t num_columns;
|
||||
uint16_t warning_count;
|
||||
|
||||
MySQL_STMT_Manager *GloMyStmt;
|
||||
|
||||
struct cpu_timer
|
||||
{
|
||||
~cpu_timer()
|
||||
{
|
||||
auto end = std::clock() ;
|
||||
std::cout << double( end - begin ) / CLOCKS_PER_SEC << " secs.\n" ;
|
||||
};
|
||||
|
||||
const std::clock_t begin = std::clock() ;
|
||||
};
|
||||
|
||||
|
||||
int run_stmt(MYSQL_STMT *stmt, int int_data) {
|
||||
MYSQL_BIND bind[1];
|
||||
MYSQL_RES *prepare_meta_result;
|
||||
bind[0].buffer_type= MYSQL_TYPE_LONG;
|
||||
bind[0].buffer= (char *)&int_data;
|
||||
bind[0].is_null= 0;
|
||||
bind[0].length= 0;
|
||||
if (mysql_stmt_bind_param(stmt, bind)) {
|
||||
fprintf(stderr, " mysql_stmt_bind_param() failed\n");
|
||||
fprintf(stderr, " %s\n", mysql_stmt_error(stmt));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
prepare_meta_result = mysql_stmt_result_metadata(stmt); // FIXME: no error check
|
||||
if (mysql_stmt_execute(stmt)) {
|
||||
fprintf(stderr, " mysql_stmt_execute(), 1 failed\n");
|
||||
fprintf(stderr, " %s\n", mysql_stmt_error(stmt));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
// memset(bind, 0, sizeof(bind));
|
||||
if (mysql_stmt_store_result(stmt)) {
|
||||
fprintf(stderr, " mysql_stmt_store_result() failed\n");
|
||||
fprintf(stderr, " %s\n", mysql_stmt_error(stmt));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
mysql_free_result(prepare_meta_result);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int main() {
|
||||
std::mt19937 mt_rand(time(0));
|
||||
GloMyStmt=new MySQL_STMT_Manager();
|
||||
MySQL_STMTs_local *local_stmts=new MySQL_STMTs_local();
|
||||
mysql = mysql_init(NULL);
|
||||
char buff[128];
|
||||
unsigned int bl=0;
|
||||
if (!mysql_real_connect(mysql,"127.0.0.1",USER,"",SCHEMA,3306,NULL,0)) {
|
||||
fprintf(stderr, "Failed to connect to database: Error: %s\n", mysql_error(mysql));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
int i;
|
||||
stmt=(MYSQL_STMT **)malloc(sizeof(MYSQL_STMT*)*NUMPREP);
|
||||
{
|
||||
cpu_timer t;
|
||||
for (i=0; i<NUMPREP; i++) {
|
||||
stmt[i] = mysql_stmt_init(mysql);
|
||||
if (!stmt[i]) {
|
||||
fprintf(stderr, " mysql_stmt_init(), out of memory\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
sprintf(buff,"SELECT %u + ?",(uint32_t)mt_rand()%NUMPRO);
|
||||
bl=strlen(buff);
|
||||
uint64_t hash=local_stmts->compute_hash(0,(char *)USER,(char *)SCHEMA,buff,bl);
|
||||
MySQL_STMT_Global_info *a=GloMyStmt->find_prepared_statement_by_hash(hash);
|
||||
if (a==NULL) {
|
||||
if (mysql_stmt_prepare(stmt[i], buff, bl)) {
|
||||
fprintf(stderr, " mysql_stmt_prepare(), failed: %s\n" , mysql_stmt_error(stmt[i]));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
uint32_t stmid=GloMyStmt->add_prepared_statement(0,(char *)USER,(char *)SCHEMA,buff,bl,stmt[i]);
|
||||
if (NUMPRO < 32)
|
||||
fprintf(stdout, "SERVER_statement_id=%lu , PROXY_statement_id=%u\n", stmt[i]->stmt_id, stmid);
|
||||
local_stmts->insert(stmid,stmt[i]);
|
||||
}
|
||||
}
|
||||
fprintf(stdout, "Prepared statements: %u client, %u proxy/server. ", NUMPREP, GloMyStmt->total_prepared_statements());
|
||||
fprintf(stdout, "Created in: ");
|
||||
}
|
||||
{
|
||||
unsigned int founds=0;
|
||||
cpu_timer t;
|
||||
for (i=0; i<NUMPREP*LOOPS; i++) {
|
||||
sprintf(buff,"SELECT %u + ?",(uint32_t)mt_rand()%NUMPRO);
|
||||
bl=strlen(buff);
|
||||
//uint64_t hash=local_stmts->compute_hash(0,(char *)USER,(char *)SCHEMA,buff,bl);
|
||||
//MySQL_STMT_Global_info *a=GloMyStmt->find_prepared_statement_by_hash(hash);
|
||||
//if (a) founds++;
|
||||
}
|
||||
fprintf(stdout, "Computed %u random strings in: ", i);
|
||||
}
|
||||
{
|
||||
unsigned int founds=0;
|
||||
cpu_timer t;
|
||||
for (i=0; i<NUMPREP*LOOPS; i++) {
|
||||
sprintf(buff,"SELECT %u + ?",(uint32_t)mt_rand()%NUMPRO);
|
||||
bl=strlen(buff);
|
||||
uint64_t hash=local_stmts->compute_hash(0,(char *)USER,(char *)SCHEMA,buff,bl);
|
||||
//MySQL_STMT_Global_info *a=GloMyStmt->find_prepared_statement_by_hash(hash);
|
||||
//if (a) founds++;
|
||||
}
|
||||
fprintf(stdout, "Computed %u hashes in: ", i);
|
||||
}
|
||||
{
|
||||
unsigned int founds=0;
|
||||
cpu_timer t;
|
||||
for (i=0; i<NUMPREP*LOOPS; i++) {
|
||||
sprintf(buff,"SELECT %u + ?",(uint32_t)mt_rand()%NUMPRO);
|
||||
bl=strlen(buff);
|
||||
uint64_t hash=local_stmts->compute_hash(0,(char *)USER,(char *)SCHEMA,buff,bl);
|
||||
MySQL_STMT_Global_info *a=GloMyStmt->find_prepared_statement_by_hash(hash);
|
||||
if (a) founds++;
|
||||
}
|
||||
fprintf(stdout, "Found %u prepared statements searching by hash in: ", founds);
|
||||
}
|
||||
{
|
||||
unsigned int founds=0;
|
||||
cpu_timer t;
|
||||
for (i=0; i<NUMPREP*LOOPS; i++) {
|
||||
sprintf(buff,"SELECT %u + ?",(uint32_t)mt_rand()%NUMPRO);
|
||||
bl=strlen(buff);
|
||||
uint64_t hash=local_stmts->compute_hash(0,(char *)USER,(char *)SCHEMA,buff,bl);
|
||||
MySQL_STMT_Global_info *a=GloMyStmt->find_prepared_statement_by_hash(hash);
|
||||
if (a) {
|
||||
// we have a prepared statement, we can run it
|
||||
founds++;
|
||||
MYSQL_STMT *stm=local_stmts->find(a->statement_id);
|
||||
run_stmt(stm,(uint32_t)mt_rand());
|
||||
}
|
||||
}
|
||||
fprintf(stdout, "Executed %u prepared statements in: ", founds);
|
||||
}
|
||||
|
||||
{
|
||||
// for comparison, we run also queries in TEXT protocol
|
||||
cpu_timer t;
|
||||
for (i=0; i<NUMPREP*LOOPS; i++) {
|
||||
sprintf(buff,"SELECT %u + %u",i,(uint32_t)mt_rand()%NUMPRO);
|
||||
bl=strlen(buff);
|
||||
int rc=mysql_real_query(mysql,buff,bl);
|
||||
if (rc) {
|
||||
fprintf(stderr, " mysql_real_query(), failed: %s\n" , mysql_error(mysql));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
MYSQL_RES *res=mysql_store_result(mysql);
|
||||
if (res==NULL) {
|
||||
fprintf(stderr, " mysql_store_result(), failed: %s\n" , mysql_error(mysql));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
mysql_free_result(res);
|
||||
}
|
||||
fprintf(stdout, "Executed %u queries in: ", i);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1,211 @@
|
||||
#include "proxysql.h"
|
||||
#include "cpp.h"
|
||||
|
||||
#include <ctime>
|
||||
#include <thread>
|
||||
|
||||
#define QUERY1 "SELECT ?"
|
||||
#define NUMPREP 100000
|
||||
#define NUMPRO 10000
|
||||
//#define NUMPREP 160
|
||||
//#define NUMPRO 4
|
||||
#define LOOPS 1
|
||||
#define USER "root"
|
||||
#define SCHEMA "test"
|
||||
|
||||
#define NTHREADS 4
|
||||
|
||||
MySQL_STMT_Manager *GloMyStmt;
|
||||
|
||||
typedef struct _thread_data_t {
|
||||
std::thread *thread;
|
||||
MYSQL *mysql;
|
||||
MYSQL_STMT **stmt;
|
||||
} thread_data_t;
|
||||
|
||||
|
||||
thread_data_t **GloThrData;
|
||||
|
||||
struct cpu_timer
|
||||
{
|
||||
~cpu_timer()
|
||||
{
|
||||
auto end = std::clock() ;
|
||||
std::cout << double( end - begin ) / CLOCKS_PER_SEC << " secs.\n" ;
|
||||
};
|
||||
|
||||
const std::clock_t begin = std::clock() ;
|
||||
};
|
||||
|
||||
|
||||
int run_stmt(MYSQL_STMT *stmt, int int_data) {
|
||||
MYSQL_BIND bind[1];
|
||||
MYSQL_RES *prepare_meta_result;
|
||||
bind[0].buffer_type= MYSQL_TYPE_LONG;
|
||||
bind[0].buffer= (char *)&int_data;
|
||||
bind[0].is_null= 0;
|
||||
bind[0].length= 0;
|
||||
if (mysql_stmt_bind_param(stmt, bind)) {
|
||||
fprintf(stderr, " mysql_stmt_bind_param() failed\n");
|
||||
fprintf(stderr, " %s\n", mysql_stmt_error(stmt));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
prepare_meta_result = mysql_stmt_result_metadata(stmt); // FIXME: no error check
|
||||
if (mysql_stmt_execute(stmt)) {
|
||||
fprintf(stderr, " mysql_stmt_execute(), 1 failed\n");
|
||||
fprintf(stderr, " %s\n", mysql_stmt_error(stmt));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
// memset(bind, 0, sizeof(bind));
|
||||
if (mysql_stmt_store_result(stmt)) {
|
||||
fprintf(stderr, " mysql_stmt_store_result() failed\n");
|
||||
fprintf(stderr, " %s\n", mysql_stmt_error(stmt));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
mysql_free_result(prepare_meta_result);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void * mysql_thread(int tid) {
|
||||
std::mt19937 mt_rand(time(0));
|
||||
|
||||
thread_data_t *THD;
|
||||
THD=GloThrData[tid];
|
||||
|
||||
MYSQL *mysql;
|
||||
MYSQL_STMT **stmt;
|
||||
|
||||
MySQL_STMTs_local *local_stmts=new MySQL_STMTs_local();
|
||||
THD->mysql = mysql_init(NULL);
|
||||
mysql=THD->mysql;
|
||||
|
||||
char buff[128];
|
||||
unsigned int bl=0;
|
||||
if (!mysql_real_connect(mysql,"127.0.0.1",USER,"",SCHEMA,3306,NULL,0)) {
|
||||
fprintf(stderr, "Failed to connect to database: Error: %s\n", mysql_error(mysql));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
int i;
|
||||
stmt=(MYSQL_STMT **)malloc(sizeof(MYSQL_STMT*)*NUMPREP);
|
||||
|
||||
{
|
||||
cpu_timer t;
|
||||
for (i=0; i<NUMPREP; i++) {
|
||||
stmt[i] = mysql_stmt_init(mysql);
|
||||
if (!stmt[i]) {
|
||||
fprintf(stderr, " mysql_stmt_init(), out of memory\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
sprintf(buff,"SELECT %u + ?",(uint32_t)mt_rand()%NUMPRO);
|
||||
bl=strlen(buff);
|
||||
uint64_t hash=local_stmts->compute_hash(0,(char *)USER,(char *)SCHEMA,buff,bl);
|
||||
MySQL_STMT_Global_info *a=GloMyStmt->find_prepared_statement_by_hash(hash);
|
||||
if (a==NULL) { // no prepared statement was found in global
|
||||
if (mysql_stmt_prepare(stmt[i], buff, bl)) { // the prepared statement is created
|
||||
fprintf(stderr, " mysql_stmt_prepare(), failed: %s\n" , mysql_stmt_error(stmt[i]));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
uint32_t stmid=GloMyStmt->add_prepared_statement(0,(char *)USER,(char *)SCHEMA,buff,bl,stmt[i]);
|
||||
if (NUMPRO < 32)
|
||||
fprintf(stdout, "SERVER_statement_id=%lu , PROXY_statement_id=%u\n", stmt[i]->stmt_id, stmid);
|
||||
local_stmts->insert(stmid,stmt[i]);
|
||||
}
|
||||
}
|
||||
fprintf(stdout, "Prepared statements: %u client, %u proxy/server. ", NUMPREP, GloMyStmt->total_prepared_statements());
|
||||
fprintf(stdout, "Created in: ");
|
||||
}
|
||||
{
|
||||
unsigned int founds=0;
|
||||
cpu_timer t;
|
||||
for (i=0; i<NUMPREP*LOOPS; i++) {
|
||||
sprintf(buff,"SELECT %u + ?",(uint32_t)mt_rand()%NUMPRO);
|
||||
bl=strlen(buff);
|
||||
//uint64_t hash=local_stmts->compute_hash(0,(char *)USER,(char *)SCHEMA,buff,bl);
|
||||
//MySQL_STMT_Global_info *a=GloMyStmt->find_prepared_statement_by_hash(hash);
|
||||
//if (a) founds++;
|
||||
}
|
||||
fprintf(stdout, "Computed %u random strings in: ", i);
|
||||
}
|
||||
{
|
||||
unsigned int founds=0;
|
||||
cpu_timer t;
|
||||
for (i=0; i<NUMPREP*LOOPS; i++) {
|
||||
sprintf(buff,"SELECT %u + ?",(uint32_t)mt_rand()%NUMPRO);
|
||||
bl=strlen(buff);
|
||||
uint64_t hash=local_stmts->compute_hash(0,(char *)USER,(char *)SCHEMA,buff,bl);
|
||||
//MySQL_STMT_Global_info *a=GloMyStmt->find_prepared_statement_by_hash(hash);
|
||||
//if (a) founds++;
|
||||
}
|
||||
fprintf(stdout, "Computed %u hashes in: ", i);
|
||||
}
|
||||
{
|
||||
unsigned int founds=0;
|
||||
cpu_timer t;
|
||||
for (i=0; i<NUMPREP*LOOPS; i++) {
|
||||
sprintf(buff,"SELECT %u + ?",(uint32_t)mt_rand()%NUMPRO);
|
||||
bl=strlen(buff);
|
||||
uint64_t hash=local_stmts->compute_hash(0,(char *)USER,(char *)SCHEMA,buff,bl);
|
||||
MySQL_STMT_Global_info *a=GloMyStmt->find_prepared_statement_by_hash(hash);
|
||||
if (a) founds++;
|
||||
}
|
||||
fprintf(stdout, "Found %u prepared statements searching by hash in: ", founds);
|
||||
}
|
||||
{
|
||||
unsigned int founds=0;
|
||||
cpu_timer t;
|
||||
for (i=0; i<NUMPREP*LOOPS; i++) {
|
||||
sprintf(buff,"SELECT %u + ?",(uint32_t)mt_rand()%NUMPRO);
|
||||
bl=strlen(buff);
|
||||
uint64_t hash=local_stmts->compute_hash(0,(char *)USER,(char *)SCHEMA,buff,bl);
|
||||
MySQL_STMT_Global_info *a=GloMyStmt->find_prepared_statement_by_hash(hash);
|
||||
if (a) {
|
||||
// we have a prepared statement, we can run it
|
||||
MYSQL_STMT *stm=local_stmts->find(a->statement_id);
|
||||
if (stm) {
|
||||
run_stmt(stm,(uint32_t)mt_rand());
|
||||
founds++;
|
||||
}
|
||||
}
|
||||
}
|
||||
fprintf(stdout, "Executed %u prepared statements in: ", founds);
|
||||
}
|
||||
|
||||
{
|
||||
// for comparison, we run also queries in TEXT protocol
|
||||
cpu_timer t;
|
||||
for (i=0; i<NUMPREP*LOOPS; i++) {
|
||||
sprintf(buff,"SELECT %u + %u",i,(uint32_t)mt_rand()%NUMPRO);
|
||||
bl=strlen(buff);
|
||||
int rc=mysql_real_query(mysql,buff,bl);
|
||||
if (rc) {
|
||||
fprintf(stderr, " mysql_real_query(), failed: %s\n" , mysql_error(mysql));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
MYSQL_RES *res=mysql_store_result(mysql);
|
||||
if (res==NULL) {
|
||||
fprintf(stderr, " mysql_store_result(), failed: %s\n" , mysql_error(mysql));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
mysql_free_result(res);
|
||||
}
|
||||
fprintf(stdout, "Executed %u queries in: ", i);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main() {
|
||||
mysql_library_init(0,NULL,NULL);
|
||||
GloMyStmt=new MySQL_STMT_Manager();
|
||||
GloThrData = (thread_data_t **)malloc(sizeof(thread_data_t *)*NTHREADS);
|
||||
|
||||
int i;
|
||||
for (i=0; i<NTHREADS; i++) {
|
||||
GloThrData[i]=(thread_data_t *)malloc(sizeof(thread_data_t));
|
||||
GloThrData[i]->thread = new std::thread(&mysql_thread,i);
|
||||
}
|
||||
for (i=0; i<NTHREADS; i++) {
|
||||
GloThrData[i]->thread->join();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1,190 @@
|
||||
#include "proxysql.h"
|
||||
#include "cpp.h"
|
||||
|
||||
#include <ctime>
|
||||
|
||||
#define QUERY1 "SELECT ?"
|
||||
#define NUMPREP 100000
|
||||
#define NUMPRO 1000
|
||||
//#define NUMPREP 160
|
||||
//#define NUMPRO 4
|
||||
#define LOOPS 10
|
||||
#define USER "root"
|
||||
#define SCHEMA "test"
|
||||
|
||||
#define NTHREADS 4
|
||||
|
||||
|
||||
typedef struct _thread_data_t {
|
||||
MYSQL *mysql;
|
||||
MYSQL_STMT **stmt;
|
||||
} thread_data_t;
|
||||
|
||||
uint32_t statement_id;
|
||||
uint16_t num_params;
|
||||
uint16_t num_columns;
|
||||
uint16_t warning_count;
|
||||
|
||||
MySQL_STMT_Manager *GloMyStmt;
|
||||
|
||||
struct cpu_timer
|
||||
{
|
||||
~cpu_timer()
|
||||
{
|
||||
auto end = std::clock() ;
|
||||
std::cout << double( end - begin ) / CLOCKS_PER_SEC << " secs.\n" ;
|
||||
};
|
||||
|
||||
const std::clock_t begin = std::clock() ;
|
||||
};
|
||||
|
||||
|
||||
int run_stmt(MYSQL_STMT *stmt, int int_data) {
|
||||
MYSQL_BIND bind[1];
|
||||
MYSQL_RES *prepare_meta_result;
|
||||
bind[0].buffer_type= MYSQL_TYPE_LONG;
|
||||
bind[0].buffer= (char *)&int_data;
|
||||
bind[0].is_null= 0;
|
||||
bind[0].length= 0;
|
||||
if (mysql_stmt_bind_param(stmt, bind)) {
|
||||
fprintf(stderr, " mysql_stmt_bind_param() failed\n");
|
||||
fprintf(stderr, " %s\n", mysql_stmt_error(stmt));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
prepare_meta_result = mysql_stmt_result_metadata(stmt); // FIXME: no error check
|
||||
if (mysql_stmt_execute(stmt)) {
|
||||
fprintf(stderr, " mysql_stmt_execute(), 1 failed\n");
|
||||
fprintf(stderr, " %s\n", mysql_stmt_error(stmt));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
// memset(bind, 0, sizeof(bind));
|
||||
if (mysql_stmt_store_result(stmt)) {
|
||||
fprintf(stderr, " mysql_stmt_store_result() failed\n");
|
||||
fprintf(stderr, " %s\n", mysql_stmt_error(stmt));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
mysql_free_result(prepare_meta_result);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void * mysql_thread() {
|
||||
std::mt19937 mt_rand(time(0));
|
||||
|
||||
|
||||
MySQL_STMTs_local *local_stmts=new MySQL_STMTs_local();
|
||||
mysql = mysql_init(NULL);
|
||||
char buff[128];
|
||||
unsigned int bl=0;
|
||||
if (!mysql_real_connect(mysql,"127.0.0.1",USER,"",SCHEMA,3306,NULL,0)) {
|
||||
fprintf(stderr, "Failed to connect to database: Error: %s\n", mysql_error(mysql));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
int i;
|
||||
stmt=(MYSQL_STMT **)malloc(sizeof(MYSQL_STMT*)*NUMPREP);
|
||||
{
|
||||
cpu_timer t;
|
||||
for (i=0; i<NUMPREP; i++) {
|
||||
stmt[i] = mysql_stmt_init(mysql);
|
||||
if (!stmt[i]) {
|
||||
fprintf(stderr, " mysql_stmt_init(), out of memory\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
sprintf(buff,"SELECT %u + ?",(uint32_t)mt_rand()%NUMPRO);
|
||||
bl=strlen(buff);
|
||||
uint64_t hash=local_stmts->compute_hash(0,(char *)USER,(char *)SCHEMA,buff,bl);
|
||||
MySQL_STMT_Global_info *a=GloMyStmt->find_prepared_statement_by_hash(hash);
|
||||
if (a==NULL) {
|
||||
if (mysql_stmt_prepare(stmt[i], buff, bl)) {
|
||||
fprintf(stderr, " mysql_stmt_prepare(), failed: %s\n" , mysql_stmt_error(stmt[i]));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
uint32_t stmid=GloMyStmt->add_prepared_statement(0,(char *)USER,(char *)SCHEMA,buff,bl,stmt[i]);
|
||||
if (NUMPRO < 32)
|
||||
fprintf(stdout, "SERVER_statement_id=%lu , PROXY_statement_id=%u\n", stmt[i]->stmt_id, stmid);
|
||||
local_stmts->insert(stmid,stmt[i]);
|
||||
}
|
||||
}
|
||||
fprintf(stdout, "Prepared statements: %u client, %u proxy/server. ", NUMPREP, GloMyStmt->total_prepared_statements());
|
||||
fprintf(stdout, "Created in: ");
|
||||
}
|
||||
{
|
||||
unsigned int founds=0;
|
||||
cpu_timer t;
|
||||
for (i=0; i<NUMPREP*LOOPS; i++) {
|
||||
sprintf(buff,"SELECT %u + ?",(uint32_t)mt_rand()%NUMPRO);
|
||||
bl=strlen(buff);
|
||||
//uint64_t hash=local_stmts->compute_hash(0,(char *)USER,(char *)SCHEMA,buff,bl);
|
||||
//MySQL_STMT_Global_info *a=GloMyStmt->find_prepared_statement_by_hash(hash);
|
||||
//if (a) founds++;
|
||||
}
|
||||
fprintf(stdout, "Computed %u random strings in: ", i);
|
||||
}
|
||||
{
|
||||
unsigned int founds=0;
|
||||
cpu_timer t;
|
||||
for (i=0; i<NUMPREP*LOOPS; i++) {
|
||||
sprintf(buff,"SELECT %u + ?",(uint32_t)mt_rand()%NUMPRO);
|
||||
bl=strlen(buff);
|
||||
uint64_t hash=local_stmts->compute_hash(0,(char *)USER,(char *)SCHEMA,buff,bl);
|
||||
//MySQL_STMT_Global_info *a=GloMyStmt->find_prepared_statement_by_hash(hash);
|
||||
//if (a) founds++;
|
||||
}
|
||||
fprintf(stdout, "Computed %u hashes in: ", i);
|
||||
}
|
||||
{
|
||||
unsigned int founds=0;
|
||||
cpu_timer t;
|
||||
for (i=0; i<NUMPREP*LOOPS; i++) {
|
||||
sprintf(buff,"SELECT %u + ?",(uint32_t)mt_rand()%NUMPRO);
|
||||
bl=strlen(buff);
|
||||
uint64_t hash=local_stmts->compute_hash(0,(char *)USER,(char *)SCHEMA,buff,bl);
|
||||
MySQL_STMT_Global_info *a=GloMyStmt->find_prepared_statement_by_hash(hash);
|
||||
if (a) founds++;
|
||||
}
|
||||
fprintf(stdout, "Found %u prepared statements searching by hash in: ", founds);
|
||||
}
|
||||
{
|
||||
unsigned int founds=0;
|
||||
cpu_timer t;
|
||||
for (i=0; i<NUMPREP*LOOPS; i++) {
|
||||
sprintf(buff,"SELECT %u + ?",(uint32_t)mt_rand()%NUMPRO);
|
||||
bl=strlen(buff);
|
||||
uint64_t hash=local_stmts->compute_hash(0,(char *)USER,(char *)SCHEMA,buff,bl);
|
||||
MySQL_STMT_Global_info *a=GloMyStmt->find_prepared_statement_by_hash(hash);
|
||||
if (a) {
|
||||
// we have a prepared statement, we can run it
|
||||
founds++;
|
||||
MYSQL_STMT *stm=local_stmts->find(a->statement_id);
|
||||
run_stmt(stm,(uint32_t)mt_rand());
|
||||
}
|
||||
}
|
||||
fprintf(stdout, "Executed %u prepared statements in: ", founds);
|
||||
}
|
||||
|
||||
{
|
||||
// for comparison, we run also queries in TEXT protocol
|
||||
cpu_timer t;
|
||||
for (i=0; i<NUMPREP*LOOPS; i++) {
|
||||
sprintf(buff,"SELECT %u + %u",i,(uint32_t)mt_rand()%NUMPRO);
|
||||
bl=strlen(buff);
|
||||
int rc=mysql_real_query(mysql,buff,bl);
|
||||
if (rc) {
|
||||
fprintf(stderr, " mysql_real_query(), failed: %s\n" , mysql_error(mysql));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
MYSQL_RES *res=mysql_store_result(mysql);
|
||||
if (res==NULL) {
|
||||
fprintf(stderr, " mysql_store_result(), failed: %s\n" , mysql_error(mysql));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
mysql_free_result(res);
|
||||
}
|
||||
fprintf(stdout, "Executed %u queries in: ", i);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main() {
|
||||
GloMyStmt=new MySQL_STMT_Manager();
|
||||
}
|
||||
@ -0,0 +1,271 @@
|
||||
#include "proxysql.h"
|
||||
#include "cpp.h"
|
||||
|
||||
#include <ctime>
|
||||
#include <thread>
|
||||
|
||||
#define QUERY1 "SELECT ?"
|
||||
#define NUMPREP 100000
|
||||
#define NUMPRO 20000
|
||||
//#define NUMPREP 160
|
||||
//#define NUMPRO 4
|
||||
#define LOOPS 1
|
||||
#define USER "root"
|
||||
#define SCHEMA "test"
|
||||
|
||||
#define NTHREADS 4
|
||||
|
||||
MySQL_STMT_Manager *GloMyStmt;
|
||||
|
||||
typedef struct _thread_data_t {
|
||||
std::thread *thread;
|
||||
MYSQL *mysql;
|
||||
MYSQL_STMT **stmt;
|
||||
} thread_data_t;
|
||||
|
||||
|
||||
thread_data_t **GloThrData;
|
||||
|
||||
struct cpu_timer
|
||||
{
|
||||
~cpu_timer()
|
||||
{
|
||||
auto end = std::clock() ;
|
||||
std::cout << double( end - begin ) / CLOCKS_PER_SEC << " secs.\n" ;
|
||||
};
|
||||
|
||||
const std::clock_t begin = std::clock() ;
|
||||
};
|
||||
|
||||
|
||||
int run_stmt(MYSQL_STMT *stmt, int int_data) {
|
||||
MYSQL_BIND bind[1];
|
||||
MYSQL_RES *prepare_meta_result;
|
||||
bind[0].buffer_type= MYSQL_TYPE_LONG;
|
||||
bind[0].buffer= (char *)&int_data;
|
||||
bind[0].is_null= 0;
|
||||
bind[0].length= 0;
|
||||
if (mysql_stmt_bind_param(stmt, bind)) {
|
||||
fprintf(stderr, " mysql_stmt_bind_param() failed\n");
|
||||
fprintf(stderr, " %s\n", mysql_stmt_error(stmt));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
prepare_meta_result = mysql_stmt_result_metadata(stmt); // FIXME: no error check
|
||||
if (mysql_stmt_execute(stmt)) {
|
||||
fprintf(stderr, " mysql_stmt_execute(), 1 failed\n");
|
||||
fprintf(stderr, " %s\n", mysql_stmt_error(stmt));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
// memset(bind, 0, sizeof(bind));
|
||||
if (mysql_stmt_store_result(stmt)) {
|
||||
fprintf(stderr, " mysql_stmt_store_result() failed\n");
|
||||
fprintf(stderr, " %s\n", mysql_stmt_error(stmt));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
mysql_free_result(prepare_meta_result);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void * mysql_thread(int tid) {
|
||||
std::mt19937 mt_rand(time(0));
|
||||
|
||||
thread_data_t *THD;
|
||||
THD=GloThrData[tid];
|
||||
|
||||
// in this version, each mysql thread has just ONE connection
|
||||
// for now we use blocking API
|
||||
MYSQL *mysql;
|
||||
|
||||
//MYSQL_STMT **stmt;
|
||||
|
||||
// we intialize the local mapping : MySQL_STMTs_local()
|
||||
MySQL_STMTs_local *local_stmts=new MySQL_STMTs_local();
|
||||
|
||||
// we initialize a MYSQL structure
|
||||
THD->mysql = mysql_init(NULL);
|
||||
mysql=THD->mysql;
|
||||
|
||||
char buff[128];
|
||||
unsigned int bl=0;
|
||||
|
||||
// we establish a connection to the database
|
||||
if (!mysql_real_connect(mysql,"127.0.0.1",USER,"",SCHEMA,3306,NULL,0)) {
|
||||
fprintf(stderr, "Failed to connect to database: Error: %s\n", mysql_error(mysql));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
int i;
|
||||
|
||||
// array of (MYSQL_STMT *) ; we don't use it in this version
|
||||
//stmt=(MYSQL_STMT **)malloc(sizeof(MYSQL_STMT*)*NUMPREP);
|
||||
|
||||
MYSQL_STMT *stmt;
|
||||
{
|
||||
cpu_timer t;
|
||||
// in this loop we create only some the prepared statements
|
||||
for (i=0; i<NUMPREP/100; i++) {
|
||||
sprintf(buff,"SELECT %u + ?",(uint32_t)mt_rand()%NUMPRO);
|
||||
bl=strlen(buff);
|
||||
uint64_t hash=local_stmts->compute_hash(0,(char *)USER,(char *)SCHEMA,buff,bl);
|
||||
MySQL_STMT_Global_info *a=GloMyStmt->find_prepared_statement_by_hash(hash);
|
||||
if (a==NULL) { // no prepared statement was found in global
|
||||
stmt = mysql_stmt_init(mysql);
|
||||
if (!stmt) {
|
||||
fprintf(stderr, " mysql_stmt_init(), out of memory\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (mysql_stmt_prepare(stmt, buff, bl)) { // the prepared statement is created
|
||||
fprintf(stderr, " mysql_stmt_prepare(), failed: %s\n" , mysql_stmt_error(stmt));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
MySQL_STMT_Global_info *stmt_info=NULL;
|
||||
stmt_info=GloMyStmt->add_prepared_statement(0,(char *)USER,(char *)SCHEMA,buff,bl,stmt);
|
||||
uint32_t stmid=stmt_info->statement_id;
|
||||
if (NUMPRO < 32)
|
||||
fprintf(stdout, "SERVER_statement_id=%lu , PROXY_statement_id=%u\n", stmt->stmt_id, stmid);
|
||||
local_stmts->insert(stmid,stmt);
|
||||
}
|
||||
}
|
||||
fprintf(stdout, "Prepared statements: %u client, %u proxy/server. ", i, GloMyStmt->total_prepared_statements());
|
||||
fprintf(stdout, "Created in: ");
|
||||
}
|
||||
{
|
||||
unsigned int founds=0;
|
||||
cpu_timer t;
|
||||
for (i=0; i<NUMPREP*LOOPS; i++) {
|
||||
sprintf(buff,"SELECT %u + ?",(uint32_t)mt_rand()%NUMPRO);
|
||||
bl=strlen(buff);
|
||||
//uint64_t hash=local_stmts->compute_hash(0,(char *)USER,(char *)SCHEMA,buff,bl);
|
||||
//MySQL_STMT_Global_info *a=GloMyStmt->find_prepared_statement_by_hash(hash);
|
||||
//if (a) founds++;
|
||||
}
|
||||
fprintf(stdout, "Computed %u random strings in: ", i);
|
||||
}
|
||||
{
|
||||
unsigned int founds=0;
|
||||
cpu_timer t;
|
||||
for (i=0; i<NUMPREP*LOOPS; i++) {
|
||||
sprintf(buff,"SELECT %u + ?",(uint32_t)mt_rand()%NUMPRO);
|
||||
bl=strlen(buff);
|
||||
uint64_t hash=local_stmts->compute_hash(0,(char *)USER,(char *)SCHEMA,buff,bl);
|
||||
//MySQL_STMT_Global_info *a=GloMyStmt->find_prepared_statement_by_hash(hash);
|
||||
//if (a) founds++;
|
||||
}
|
||||
fprintf(stdout, "Computed %u hashes in: ", i);
|
||||
}
|
||||
{
|
||||
unsigned int founds=0;
|
||||
cpu_timer t;
|
||||
for (i=0; i<NUMPREP*LOOPS; i++) {
|
||||
sprintf(buff,"SELECT %u + ?",(uint32_t)mt_rand()%NUMPRO);
|
||||
bl=strlen(buff);
|
||||
uint64_t hash=local_stmts->compute_hash(0,(char *)USER,(char *)SCHEMA,buff,bl);
|
||||
MySQL_STMT_Global_info *a=GloMyStmt->find_prepared_statement_by_hash(hash);
|
||||
if (a) founds++;
|
||||
}
|
||||
fprintf(stdout, "Found %u prepared statements searching by hash in: ", founds);
|
||||
}
|
||||
|
||||
{
|
||||
unsigned int founds=0;
|
||||
unsigned int created=0;
|
||||
unsigned int executed=0;
|
||||
cpu_timer t;
|
||||
for (i=0; i<NUMPREP*LOOPS; i++) {
|
||||
sprintf(buff,"SELECT %u + ?",(uint32_t)mt_rand()%NUMPRO);
|
||||
bl=strlen(buff);
|
||||
uint64_t hash=local_stmts->compute_hash(0,(char *)USER,(char *)SCHEMA,buff,bl);
|
||||
MySQL_STMT_Global_info *a=GloMyStmt->find_prepared_statement_by_hash(hash);
|
||||
if (a) {
|
||||
// we have a prepared statement, we can run it
|
||||
MYSQL_STMT *stm=local_stmts->find(a->statement_id);
|
||||
if (stm) { // the statement exists in local
|
||||
run_stmt(stm,(uint32_t)mt_rand());
|
||||
founds++;
|
||||
executed++;
|
||||
local_stmts->erase(a->statement_id);
|
||||
} else { // the statement doesn't exist locally
|
||||
stmt = mysql_stmt_init(mysql);
|
||||
if (!stmt) {
|
||||
fprintf(stderr, " mysql_stmt_init(), out of memory\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (mysql_stmt_prepare(stmt, buff, bl)) { // the prepared statement is created
|
||||
fprintf(stderr, " mysql_stmt_prepare(), failed: %s\n" , mysql_stmt_error(stmt));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
local_stmts->insert(a->statement_id,stmt);
|
||||
run_stmt(stmt,(uint32_t)mt_rand());
|
||||
created++;
|
||||
executed++;
|
||||
local_stmts->erase(a->statement_id);
|
||||
}
|
||||
} else { // no prepared statement was found in global
|
||||
stmt = mysql_stmt_init(mysql);
|
||||
if (!stmt) {
|
||||
fprintf(stderr, " mysql_stmt_init(), out of memory\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (mysql_stmt_prepare(stmt, buff, bl)) { // the prepared statement is created
|
||||
fprintf(stderr, " mysql_stmt_prepare(), failed: %s\n" , mysql_stmt_error(stmt));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
MySQL_STMT_Global_info *stmt_info=NULL;
|
||||
stmt_info=GloMyStmt->add_prepared_statement(0,(char *)USER,(char *)SCHEMA,buff,bl,stmt);
|
||||
uint32_t stmid=stmt_info->statement_id;
|
||||
if (NUMPRO < 32)
|
||||
fprintf(stdout, "SERVER_statement_id=%lu , PROXY_statement_id=%u\n", stmt->stmt_id, stmid);
|
||||
local_stmts->insert(stmid,stmt);
|
||||
run_stmt(stmt,(uint32_t)mt_rand());
|
||||
created++;
|
||||
executed++;
|
||||
local_stmts->erase(stmid);
|
||||
}
|
||||
}
|
||||
fprintf(stdout, "Found %u , created %u and executed %u prepared statements in: ", founds, created, executed);
|
||||
}
|
||||
/*
|
||||
{
|
||||
// for comparison, we run also queries in TEXT protocol
|
||||
cpu_timer t;
|
||||
for (i=0; i<NUMPREP*LOOPS; i++) {
|
||||
sprintf(buff,"SELECT %u + %u",i,(uint32_t)mt_rand()%NUMPRO);
|
||||
bl=strlen(buff);
|
||||
int rc=mysql_real_query(mysql,buff,bl);
|
||||
if (rc) {
|
||||
fprintf(stderr, " mysql_real_query(), failed: %s\n" , mysql_error(mysql));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
MYSQL_RES *res=mysql_store_result(mysql);
|
||||
if (res==NULL) {
|
||||
fprintf(stderr, " mysql_store_result(), failed: %s\n" , mysql_error(mysql));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
mysql_free_result(res);
|
||||
}
|
||||
fprintf(stdout, "Executed %u queries in: ", i);
|
||||
}
|
||||
return 0;
|
||||
*/
|
||||
}
|
||||
|
||||
int main() {
|
||||
// initialize mysql
|
||||
mysql_library_init(0,NULL,NULL);
|
||||
|
||||
// create a new MySQL_STMT_Manager()
|
||||
GloMyStmt=new MySQL_STMT_Manager();
|
||||
GloThrData = (thread_data_t **)malloc(sizeof(thread_data_t *)*NTHREADS);
|
||||
|
||||
// starts N threads
|
||||
int i;
|
||||
for (i=0; i<NTHREADS; i++) {
|
||||
GloThrData[i]=(thread_data_t *)malloc(sizeof(thread_data_t));
|
||||
GloThrData[i]->thread = new std::thread(&mysql_thread,i);
|
||||
}
|
||||
// wait for the threads to complete
|
||||
for (i=0; i<NTHREADS; i++) {
|
||||
GloThrData[i]->thread->join();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1,357 @@
|
||||
#define PROXYSQL_EXTERN
|
||||
#include "proxysql.h"
|
||||
#include "cpp.h"
|
||||
|
||||
#include <ctime>
|
||||
#include <thread>
|
||||
|
||||
#define QUERY1 "SELECT ?"
|
||||
#define NUMPREP 100000
|
||||
#define NUMPRO 20000
|
||||
//#define NUMPREP 160
|
||||
//#define NUMPRO 4
|
||||
#define LOOPS 1
|
||||
#define USER "root"
|
||||
#define SCHEMA "test"
|
||||
|
||||
#define NTHREADS 4
|
||||
|
||||
MySQL_STMT_Manager *GloMyStmt;
|
||||
Query_Cache *GloQC;
|
||||
MySQL_Authentication *GloMyAuth;
|
||||
Query_Processor *GloQPro;
|
||||
ProxySQL_Admin *GloAdmin;
|
||||
MySQL_Threads_Handler *GloMTH;
|
||||
MySQL_Monitor *GloMyMon;
|
||||
std::thread *MyMon_thread;
|
||||
|
||||
MySQL_Logger *GloMyLogger;
|
||||
|
||||
|
||||
typedef struct _thread_data_t {
|
||||
std::thread *thread;
|
||||
MYSQL *mysql;
|
||||
MYSQL_STMT **stmt;
|
||||
} thread_data_t;
|
||||
|
||||
|
||||
thread_data_t **GloThrData;
|
||||
|
||||
struct cpu_timer
|
||||
{
|
||||
~cpu_timer()
|
||||
{
|
||||
auto end = std::clock() ;
|
||||
std::cout << double( end - begin ) / CLOCKS_PER_SEC << " secs.\n" ;
|
||||
};
|
||||
|
||||
const std::clock_t begin = std::clock() ;
|
||||
};
|
||||
|
||||
|
||||
int run_stmt(MYSQL_STMT *stmt, int int_data) {
|
||||
MYSQL_BIND bind[1];
|
||||
MYSQL_RES *prepare_meta_result;
|
||||
bind[0].buffer_type= MYSQL_TYPE_LONG;
|
||||
bind[0].buffer= (char *)&int_data;
|
||||
bind[0].is_null= 0;
|
||||
bind[0].length= 0;
|
||||
if (mysql_stmt_bind_param(stmt, bind)) {
|
||||
fprintf(stderr, " mysql_stmt_bind_param() failed\n");
|
||||
fprintf(stderr, " %s\n", mysql_stmt_error(stmt));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
prepare_meta_result = mysql_stmt_result_metadata(stmt); // FIXME: no error check
|
||||
if (mysql_stmt_execute(stmt)) {
|
||||
fprintf(stderr, " mysql_stmt_execute(), 1 failed\n");
|
||||
fprintf(stderr, " %s\n", mysql_stmt_error(stmt));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
// memset(bind, 0, sizeof(bind));
|
||||
if (mysql_stmt_store_result(stmt)) {
|
||||
fprintf(stderr, " mysql_stmt_store_result() failed\n");
|
||||
fprintf(stderr, " %s\n", mysql_stmt_error(stmt));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
mysql_free_result(prepare_meta_result);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void * mysql_thread(int tid) {
|
||||
std::mt19937 mt_rand(time(0));
|
||||
|
||||
|
||||
thread_data_t *THD;
|
||||
THD=GloThrData[tid];
|
||||
|
||||
MySQL_Thread *worker = new MySQL_Thread();
|
||||
worker->init();
|
||||
|
||||
char buff[128];
|
||||
unsigned int bl=0;
|
||||
|
||||
MySrvC *mysrvc=new MySrvC((char *)"127.0.0.1", 3306, 100, MYSQL_SERVER_STATUS_ONLINE, 100, 0, 0, 0, 10000);
|
||||
|
||||
{
|
||||
int i;
|
||||
MySQL_Session **SESS=(MySQL_Session **)malloc(16*sizeof(MySQL_Session *));
|
||||
|
||||
for (i=0; i<16; i++) {
|
||||
SESS[i]=new MySQL_Session();
|
||||
MySQL_Session *sess=SESS[i];
|
||||
sess->mirror==true;
|
||||
sess->client_myds=NULL;
|
||||
sess->client_myds = new MySQL_Data_Stream();
|
||||
sess->client_myds->DSS=STATE_SLEEP;
|
||||
sess->client_myds->sess=sess;
|
||||
sess->client_myds->myds_type=MYDS_FRONTEND;
|
||||
sess->client_myds->PSarrayIN= new PtrSizeArray();
|
||||
sess->client_myds->PSarrayOUT= new PtrSizeArray();
|
||||
worker->register_session(sess);
|
||||
sess->current_hostgroup=0;
|
||||
sess->default_hostgroup=0;
|
||||
sess->mybe=sess->find_or_create_backend(sess->current_hostgroup);
|
||||
MySQL_Connection *myconn=new MySQL_Connection();
|
||||
sess->mybe->server_myds->attach_connection(myconn);
|
||||
myconn->userinfo->set((char *)"root",(char *)"",(char *)"information_schema");
|
||||
myconn->local_stmts = new MySQL_STMTs_local();
|
||||
//myconn->mysql=mysql_init(NULL);
|
||||
myconn->parent=mysrvc;
|
||||
/*
|
||||
if (!mysql_real_connect(myconn->mysql,"127.0.0.1",USER,"",SCHEMA,3306,NULL,0)) {
|
||||
fprintf(stderr, "Failed to connect to database: Error: %s\n", mysql_error(myconn->mysql));
|
||||
exit(EXIT_FAILURE);
|
||||
}*/
|
||||
myconn->handler(0);
|
||||
if (myconn->mysql==NULL) {
|
||||
myconn->handler(0);
|
||||
}
|
||||
}
|
||||
for (i=0; i<16; i++) {
|
||||
MySQL_Session *sess=SESS[i];
|
||||
sprintf(buff+5,"SELECT %u + ?",(uint32_t)mt_rand()%NUMPRO);
|
||||
bl=strlen(buff+5);
|
||||
mysql_hdr hdr;
|
||||
hdr.pkt_id=0;
|
||||
hdr.pkt_length=bl+1;
|
||||
memcpy(buff,&hdr,sizeof(mysql_hdr));
|
||||
buff[4]=0x16;
|
||||
PtrSize_t pkt;
|
||||
pkt.size=hdr.pkt_length+sizeof(mysql_hdr);
|
||||
pkt.ptr=malloc(pkt.size);
|
||||
memcpy(pkt.ptr,buff,pkt.size);
|
||||
sess->client_myds->PSarrayIN->add(pkt.ptr,pkt.size);
|
||||
sess->status=WAITING_CLIENT_DATA;;
|
||||
sess->handler();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
// in this version, each mysql thread has just ONE connection
|
||||
// for now we use blocking API
|
||||
MYSQL *mysql;
|
||||
|
||||
//MYSQL_STMT **stmt;
|
||||
|
||||
// we intialize the local mapping : MySQL_STMTs_local()
|
||||
MySQL_STMTs_local *local_stmts=new MySQL_STMTs_local();
|
||||
|
||||
// we initialize a MYSQL structure
|
||||
THD->mysql = mysql_init(NULL);
|
||||
mysql=THD->mysql;
|
||||
|
||||
char buff[128];
|
||||
unsigned int bl=0;
|
||||
|
||||
// we establish a connection to the database
|
||||
if (!mysql_real_connect(mysql,"127.0.0.1",USER,"",SCHEMA,3306,NULL,0)) {
|
||||
fprintf(stderr, "Failed to connect to database: Error: %s\n", mysql_error(mysql));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
int i;
|
||||
|
||||
// array of (MYSQL_STMT *) ; we don't use it in this version
|
||||
//stmt=(MYSQL_STMT **)malloc(sizeof(MYSQL_STMT*)*NUMPREP);
|
||||
|
||||
MYSQL_STMT *stmt;
|
||||
{
|
||||
cpu_timer t;
|
||||
// in this loop we create only some the prepared statements
|
||||
for (i=0; i<NUMPREP/100; i++) {
|
||||
sprintf(buff,"SELECT %u + ?",(uint32_t)mt_rand()%NUMPRO);
|
||||
bl=strlen(buff);
|
||||
uint64_t hash=local_stmts->compute_hash(0,(char *)USER,(char *)SCHEMA,buff,bl);
|
||||
MySQL_STMT_Global_info *a=GloMyStmt->find_prepared_statement_by_hash(hash);
|
||||
if (a==NULL) { // no prepared statement was found in global
|
||||
stmt = mysql_stmt_init(mysql);
|
||||
if (!stmt) {
|
||||
fprintf(stderr, " mysql_stmt_init(), out of memory\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (mysql_stmt_prepare(stmt, buff, bl)) { // the prepared statement is created
|
||||
fprintf(stderr, " mysql_stmt_prepare(), failed: %s\n" , mysql_stmt_error(stmt));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
uint32_t stmid=GloMyStmt->add_prepared_statement(0,(char *)USER,(char *)SCHEMA,buff,bl,stmt);
|
||||
if (NUMPRO < 32)
|
||||
fprintf(stdout, "SERVER_statement_id=%lu , PROXY_statement_id=%u\n", stmt->stmt_id, stmid);
|
||||
local_stmts->insert(stmid,stmt);
|
||||
}
|
||||
}
|
||||
fprintf(stdout, "Prepared statements: %u client, %u proxy/server. ", i, GloMyStmt->total_prepared_statements());
|
||||
fprintf(stdout, "Created in: ");
|
||||
}
|
||||
{
|
||||
unsigned int founds=0;
|
||||
cpu_timer t;
|
||||
for (i=0; i<NUMPREP*LOOPS; i++) {
|
||||
sprintf(buff,"SELECT %u + ?",(uint32_t)mt_rand()%NUMPRO);
|
||||
bl=strlen(buff);
|
||||
//uint64_t hash=local_stmts->compute_hash(0,(char *)USER,(char *)SCHEMA,buff,bl);
|
||||
//MySQL_STMT_Global_info *a=GloMyStmt->find_prepared_statement_by_hash(hash);
|
||||
//if (a) founds++;
|
||||
}
|
||||
fprintf(stdout, "Computed %u random strings in: ", i);
|
||||
}
|
||||
{
|
||||
unsigned int founds=0;
|
||||
cpu_timer t;
|
||||
for (i=0; i<NUMPREP*LOOPS; i++) {
|
||||
sprintf(buff,"SELECT %u + ?",(uint32_t)mt_rand()%NUMPRO);
|
||||
bl=strlen(buff);
|
||||
uint64_t hash=local_stmts->compute_hash(0,(char *)USER,(char *)SCHEMA,buff,bl);
|
||||
//MySQL_STMT_Global_info *a=GloMyStmt->find_prepared_statement_by_hash(hash);
|
||||
//if (a) founds++;
|
||||
}
|
||||
fprintf(stdout, "Computed %u hashes in: ", i);
|
||||
}
|
||||
{
|
||||
unsigned int founds=0;
|
||||
cpu_timer t;
|
||||
for (i=0; i<NUMPREP*LOOPS; i++) {
|
||||
sprintf(buff,"SELECT %u + ?",(uint32_t)mt_rand()%NUMPRO);
|
||||
bl=strlen(buff);
|
||||
uint64_t hash=local_stmts->compute_hash(0,(char *)USER,(char *)SCHEMA,buff,bl);
|
||||
MySQL_STMT_Global_info *a=GloMyStmt->find_prepared_statement_by_hash(hash);
|
||||
if (a) founds++;
|
||||
}
|
||||
fprintf(stdout, "Found %u prepared statements searching by hash in: ", founds);
|
||||
}
|
||||
|
||||
{
|
||||
unsigned int founds=0;
|
||||
unsigned int created=0;
|
||||
unsigned int executed=0;
|
||||
cpu_timer t;
|
||||
for (i=0; i<NUMPREP*LOOPS; i++) {
|
||||
sprintf(buff,"SELECT %u + ?",(uint32_t)mt_rand()%NUMPRO);
|
||||
bl=strlen(buff);
|
||||
uint64_t hash=local_stmts->compute_hash(0,(char *)USER,(char *)SCHEMA,buff,bl);
|
||||
MySQL_STMT_Global_info *a=GloMyStmt->find_prepared_statement_by_hash(hash);
|
||||
if (a) {
|
||||
// we have a prepared statement, we can run it
|
||||
MYSQL_STMT *stm=local_stmts->find(a->statement_id);
|
||||
if (stm) { // the statement exists in local
|
||||
run_stmt(stm,(uint32_t)mt_rand());
|
||||
founds++;
|
||||
executed++;
|
||||
local_stmts->erase(a->statement_id);
|
||||
} else { // the statement doesn't exist locally
|
||||
stmt = mysql_stmt_init(mysql);
|
||||
if (!stmt) {
|
||||
fprintf(stderr, " mysql_stmt_init(), out of memory\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (mysql_stmt_prepare(stmt, buff, bl)) { // the prepared statement is created
|
||||
fprintf(stderr, " mysql_stmt_prepare(), failed: %s\n" , mysql_stmt_error(stmt));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
local_stmts->insert(a->statement_id,stmt);
|
||||
run_stmt(stmt,(uint32_t)mt_rand());
|
||||
created++;
|
||||
executed++;
|
||||
local_stmts->erase(a->statement_id);
|
||||
}
|
||||
} else { // no prepared statement was found in global
|
||||
stmt = mysql_stmt_init(mysql);
|
||||
if (!stmt) {
|
||||
fprintf(stderr, " mysql_stmt_init(), out of memory\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (mysql_stmt_prepare(stmt, buff, bl)) { // the prepared statement is created
|
||||
fprintf(stderr, " mysql_stmt_prepare(), failed: %s\n" , mysql_stmt_error(stmt));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
uint32_t stmid=GloMyStmt->add_prepared_statement(0,(char *)USER,(char *)SCHEMA,buff,bl,stmt);
|
||||
if (NUMPRO < 32)
|
||||
fprintf(stdout, "SERVER_statement_id=%lu , PROXY_statement_id=%u\n", stmt->stmt_id, stmid);
|
||||
local_stmts->insert(stmid,stmt);
|
||||
run_stmt(stmt,(uint32_t)mt_rand());
|
||||
created++;
|
||||
executed++;
|
||||
local_stmts->erase(stmid);
|
||||
}
|
||||
}
|
||||
fprintf(stdout, "Found %u , created %u and executed %u prepared statements in: ", founds, created, executed);
|
||||
}
|
||||
*/
|
||||
/*
|
||||
{
|
||||
// for comparison, we run also queries in TEXT protocol
|
||||
cpu_timer t;
|
||||
for (i=0; i<NUMPREP*LOOPS; i++) {
|
||||
sprintf(buff,"SELECT %u + %u",i,(uint32_t)mt_rand()%NUMPRO);
|
||||
bl=strlen(buff);
|
||||
int rc=mysql_real_query(mysql,buff,bl);
|
||||
if (rc) {
|
||||
fprintf(stderr, " mysql_real_query(), failed: %s\n" , mysql_error(mysql));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
MYSQL_RES *res=mysql_store_result(mysql);
|
||||
if (res==NULL) {
|
||||
fprintf(stderr, " mysql_store_result(), failed: %s\n" , mysql_error(mysql));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
mysql_free_result(res);
|
||||
}
|
||||
fprintf(stdout, "Executed %u queries in: ", i);
|
||||
}
|
||||
return 0;
|
||||
*/
|
||||
}
|
||||
|
||||
int main() {
|
||||
// initialize mysql
|
||||
mysql_library_init(0,NULL,NULL);
|
||||
|
||||
sqlite3_config(SQLITE_CONFIG_URI, 1);
|
||||
|
||||
MyHGM=new MySQL_HostGroups_Manager();
|
||||
GloMTH=new MySQL_Threads_Handler();
|
||||
GloMyLogger = new MySQL_Logger();
|
||||
|
||||
GloVars.datadir=(char *)".";
|
||||
GloVars.admindb=(char *)"proxysql.db";
|
||||
GloAdmin = new ProxySQL_Admin();
|
||||
GloAdmin->init();
|
||||
|
||||
// create a new MySQL_STMT_Manager()
|
||||
GloMyStmt=new MySQL_STMT_Manager();
|
||||
GloThrData = (thread_data_t **)malloc(sizeof(thread_data_t *)*NTHREADS);
|
||||
|
||||
// starts N threads
|
||||
int i;
|
||||
for (i=0; i<NTHREADS; i++) {
|
||||
GloThrData[i]=(thread_data_t *)malloc(sizeof(thread_data_t));
|
||||
GloThrData[i]->thread = new std::thread(&mysql_thread,i);
|
||||
}
|
||||
while (glovars.shutdown==0) {
|
||||
sleep(1); // FIXME: TERRIBLE UGLY
|
||||
}
|
||||
// wait for the threads to complete
|
||||
for (i=0; i<NTHREADS; i++) {
|
||||
GloThrData[i]->thread->join();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1,369 @@
|
||||
/*
|
||||
this is a modified version of client5.cpp
|
||||
that supports async calls
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include "proxysql.h"
|
||||
#include "cpp.h"
|
||||
|
||||
#include <ctime>
|
||||
#include <thread>
|
||||
|
||||
#define QUERY1 "SELECT ?"
|
||||
#define NUMPREP 100000
|
||||
#define NUMPRO 20000
|
||||
//#define NUMPREP 160
|
||||
//#define NUMPRO 4
|
||||
#define LOOPS 1
|
||||
#define USER "root"
|
||||
#define SCHEMA "test"
|
||||
|
||||
#define NTHREADS 4
|
||||
|
||||
static int wait_for_mysql(MYSQL *mysql, int status) {
|
||||
struct pollfd pfd;
|
||||
int timeout, res;
|
||||
|
||||
pfd.fd = mysql_get_socket(mysql);
|
||||
pfd.events =
|
||||
(status & MYSQL_WAIT_READ ? POLLIN : 0) |
|
||||
(status & MYSQL_WAIT_WRITE ? POLLOUT : 0) |
|
||||
(status & MYSQL_WAIT_EXCEPT ? POLLPRI : 0);
|
||||
// if (status & MYSQL_WAIT_TIMEOUT)
|
||||
// timeout = 1000*mysql_get_timeout_value(mysql);
|
||||
// else
|
||||
timeout = -1;
|
||||
res = poll(&pfd, 1, timeout);
|
||||
if (res == 0)
|
||||
return MYSQL_WAIT_TIMEOUT;
|
||||
else if (res < 0)
|
||||
return MYSQL_WAIT_TIMEOUT;
|
||||
else {
|
||||
int status = 0;
|
||||
if (pfd.revents & POLLIN) status |= MYSQL_WAIT_READ;
|
||||
if (pfd.revents & POLLOUT) status |= MYSQL_WAIT_WRITE;
|
||||
if (pfd.revents & POLLPRI) status |= MYSQL_WAIT_EXCEPT;
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
MySQL_STMT_Manager *GloMyStmt;
|
||||
|
||||
typedef struct _thread_data_t {
|
||||
std::thread *thread;
|
||||
MYSQL *mysql;
|
||||
MYSQL_STMT **stmt;
|
||||
} thread_data_t;
|
||||
|
||||
|
||||
thread_data_t **GloThrData;
|
||||
|
||||
struct cpu_timer
|
||||
{
|
||||
~cpu_timer()
|
||||
{
|
||||
auto end = std::clock() ;
|
||||
std::cout << double( end - begin ) / CLOCKS_PER_SEC << " secs.\n" ;
|
||||
};
|
||||
|
||||
const std::clock_t begin = std::clock() ;
|
||||
};
|
||||
|
||||
|
||||
int run_stmt(MYSQL *mysql, MYSQL_STMT *stmt, int int_data) {
|
||||
int async_exit_status=0;
|
||||
int ret_int;
|
||||
MYSQL_BIND bind[1];
|
||||
MYSQL_RES *prepare_meta_result;
|
||||
bind[0].buffer_type= MYSQL_TYPE_LONG;
|
||||
bind[0].buffer= (char *)&int_data;
|
||||
bind[0].is_null= 0;
|
||||
bind[0].length= 0;
|
||||
if (mysql_stmt_bind_param(stmt, bind)) {
|
||||
fprintf(stderr, " mysql_stmt_bind_param() failed\n");
|
||||
fprintf(stderr, " %s\n", mysql_stmt_error(stmt));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
prepare_meta_result = mysql_stmt_result_metadata(stmt); // FIXME: no error check
|
||||
/* blocking
|
||||
if (mysql_stmt_execute(stmt)) {
|
||||
fprintf(stderr, " mysql_stmt_execute(), 1 failed\n");
|
||||
fprintf(stderr, " %s\n", mysql_stmt_error(stmt));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (mysql_stmt_store_result(stmt)) {
|
||||
fprintf(stderr, " mysql_stmt_store_result() failed\n");
|
||||
fprintf(stderr, " %s\n", mysql_stmt_error(stmt));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
*/
|
||||
async_exit_status=mysql_stmt_execute_start(&ret_int, stmt);
|
||||
while (async_exit_status) {
|
||||
async_exit_status=wait_for_mysql(mysql, async_exit_status);
|
||||
async_exit_status=mysql_stmt_execute_cont(&ret_int, stmt, async_exit_status);
|
||||
}
|
||||
if (ret_int) {
|
||||
fprintf(stderr, " mysql_stmt_execute(), 1 failed\n");
|
||||
fprintf(stderr, " %s\n", mysql_stmt_error(stmt));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
async_exit_status=mysql_stmt_store_result_start(&ret_int, stmt);
|
||||
while (async_exit_status) {
|
||||
async_exit_status=wait_for_mysql(mysql, async_exit_status);
|
||||
async_exit_status=mysql_stmt_store_result_cont(&ret_int, stmt, async_exit_status);
|
||||
}
|
||||
if (ret_int) {
|
||||
fprintf(stderr, " mysql_stmt_store_result() failed\n");
|
||||
fprintf(stderr, " %s\n", mysql_stmt_error(stmt));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
mysql_free_result(prepare_meta_result);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void * mysql_thread(int tid) {
|
||||
std::mt19937 mt_rand(time(0));
|
||||
|
||||
thread_data_t *THD;
|
||||
THD=GloThrData[tid];
|
||||
|
||||
// in this version, each mysql thread has just ONE connection
|
||||
// for now we use blocking API
|
||||
MYSQL *mysql;
|
||||
|
||||
//MYSQL_STMT **stmt;
|
||||
|
||||
// we intialize the local mapping : MySQL_STMTs_local()
|
||||
MySQL_STMTs_local *local_stmts=new MySQL_STMTs_local();
|
||||
|
||||
// we initialize a MYSQL structure
|
||||
THD->mysql = mysql_init(NULL);
|
||||
mysql=THD->mysql;
|
||||
|
||||
char buff[128];
|
||||
unsigned int bl=0;
|
||||
|
||||
// we establish a connection to the database
|
||||
if (!mysql_real_connect(mysql,"127.0.0.1",USER,"",SCHEMA,3306,NULL,0)) {
|
||||
fprintf(stderr, "Failed to connect to database: Error: %s\n", mysql_error(mysql));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
int i;
|
||||
//set not blocking
|
||||
mysql_options(mysql, MYSQL_OPT_NONBLOCK, 0);
|
||||
int async_exit_status=0;
|
||||
int ret_int;
|
||||
// array of (MYSQL_STMT *) ; we don't use it in this version
|
||||
//stmt=(MYSQL_STMT **)malloc(sizeof(MYSQL_STMT*)*NUMPREP);
|
||||
|
||||
MYSQL_STMT *stmt;
|
||||
{
|
||||
cpu_timer t;
|
||||
// in this loop we create only some the prepared statements
|
||||
for (i=0; i<NUMPREP/100; i++) {
|
||||
sprintf(buff,"SELECT %u + ?",(uint32_t)mt_rand()%NUMPRO);
|
||||
bl=strlen(buff);
|
||||
uint64_t hash=local_stmts->compute_hash(0,(char *)USER,(char *)SCHEMA,buff,bl);
|
||||
MySQL_STMT_Global_info *a=GloMyStmt->find_prepared_statement_by_hash(hash);
|
||||
if (a==NULL) { // no prepared statement was found in global
|
||||
stmt = mysql_stmt_init(mysql);
|
||||
if (!stmt) {
|
||||
fprintf(stderr, " mysql_stmt_init(), out of memory\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
/* blocking call
|
||||
if (mysql_stmt_prepare(stmt, buff, bl)) { // the prepared statement is created
|
||||
fprintf(stderr, " mysql_stmt_prepare(), failed: %s\n" , mysql_stmt_error(stmt));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
*/
|
||||
async_exit_status=mysql_stmt_prepare_start(&ret_int, stmt, buff, bl);
|
||||
while (async_exit_status) {
|
||||
async_exit_status=wait_for_mysql(mysql, async_exit_status);
|
||||
async_exit_status=mysql_stmt_prepare_cont(&ret_int, stmt, async_exit_status);
|
||||
}
|
||||
if (ret_int) {
|
||||
fprintf(stderr, " mysql_stmt_prepare(), failed: %s\n" , mysql_stmt_error(stmt));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
MySQL_STMT_Global_info *stmt_info=NULL;
|
||||
stmt_info=GloMyStmt->add_prepared_statement(0,(char *)USER,(char *)SCHEMA,buff,bl,stmt);
|
||||
uint32_t stmid=stmt_info->statement_id;
|
||||
if (NUMPRO < 32)
|
||||
fprintf(stdout, "SERVER_statement_id=%lu , PROXY_statement_id=%u\n", stmt->stmt_id, stmid);
|
||||
local_stmts->insert(stmid,stmt);
|
||||
}
|
||||
}
|
||||
fprintf(stdout, "Prepared statements: %u client, %u proxy/server. ", i, GloMyStmt->total_prepared_statements());
|
||||
fprintf(stdout, "Created in: ");
|
||||
}
|
||||
{
|
||||
unsigned int founds=0;
|
||||
cpu_timer t;
|
||||
for (i=0; i<NUMPREP*LOOPS; i++) {
|
||||
sprintf(buff,"SELECT %u + ?",(uint32_t)mt_rand()%NUMPRO);
|
||||
bl=strlen(buff);
|
||||
//uint64_t hash=local_stmts->compute_hash(0,(char *)USER,(char *)SCHEMA,buff,bl);
|
||||
//MySQL_STMT_Global_info *a=GloMyStmt->find_prepared_statement_by_hash(hash);
|
||||
//if (a) founds++;
|
||||
}
|
||||
fprintf(stdout, "Computed %u random strings in: ", i);
|
||||
}
|
||||
{
|
||||
unsigned int founds=0;
|
||||
cpu_timer t;
|
||||
for (i=0; i<NUMPREP*LOOPS; i++) {
|
||||
sprintf(buff,"SELECT %u + ?",(uint32_t)mt_rand()%NUMPRO);
|
||||
bl=strlen(buff);
|
||||
uint64_t hash=local_stmts->compute_hash(0,(char *)USER,(char *)SCHEMA,buff,bl);
|
||||
//MySQL_STMT_Global_info *a=GloMyStmt->find_prepared_statement_by_hash(hash);
|
||||
//if (a) founds++;
|
||||
}
|
||||
fprintf(stdout, "Computed %u hashes in: ", i);
|
||||
}
|
||||
{
|
||||
unsigned int founds=0;
|
||||
cpu_timer t;
|
||||
for (i=0; i<NUMPREP*LOOPS; i++) {
|
||||
sprintf(buff,"SELECT %u + ?",(uint32_t)mt_rand()%NUMPRO);
|
||||
bl=strlen(buff);
|
||||
uint64_t hash=local_stmts->compute_hash(0,(char *)USER,(char *)SCHEMA,buff,bl);
|
||||
MySQL_STMT_Global_info *a=GloMyStmt->find_prepared_statement_by_hash(hash);
|
||||
if (a) founds++;
|
||||
}
|
||||
fprintf(stdout, "Found %u prepared statements searching by hash in: ", founds);
|
||||
}
|
||||
|
||||
{
|
||||
unsigned int founds=0;
|
||||
unsigned int created=0;
|
||||
unsigned int executed=0;
|
||||
cpu_timer t;
|
||||
for (i=0; i<NUMPREP*LOOPS; i++) {
|
||||
sprintf(buff,"SELECT %u + ?",(uint32_t)mt_rand()%NUMPRO);
|
||||
bl=strlen(buff);
|
||||
uint64_t hash=local_stmts->compute_hash(0,(char *)USER,(char *)SCHEMA,buff,bl);
|
||||
MySQL_STMT_Global_info *a=GloMyStmt->find_prepared_statement_by_hash(hash);
|
||||
if (a) {
|
||||
// we have a prepared statement, we can run it
|
||||
MYSQL_STMT *stm=local_stmts->find(a->statement_id);
|
||||
if (stm) { // the statement exists in local
|
||||
run_stmt(mysql, stm,(uint32_t)mt_rand());
|
||||
founds++;
|
||||
executed++;
|
||||
local_stmts->erase(a->statement_id);
|
||||
} else { // the statement doesn't exist locally
|
||||
stmt = mysql_stmt_init(mysql);
|
||||
if (!stmt) {
|
||||
fprintf(stderr, " mysql_stmt_init(), out of memory\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
/* blocking
|
||||
if (mysql_stmt_prepare(stmt, buff, bl)) { // the prepared statement is created
|
||||
fprintf(stderr, " mysql_stmt_prepare(), failed: %s\n" , mysql_stmt_error(stmt));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
*/
|
||||
async_exit_status=mysql_stmt_prepare_start(&ret_int, stmt, buff, bl);
|
||||
while (async_exit_status) {
|
||||
async_exit_status=wait_for_mysql(mysql, async_exit_status);
|
||||
async_exit_status=mysql_stmt_prepare_cont(&ret_int, stmt, async_exit_status);
|
||||
}
|
||||
if (ret_int) {
|
||||
fprintf(stderr, " mysql_stmt_prepare(), failed: %s\n" , mysql_stmt_error(stmt));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
local_stmts->insert(a->statement_id,stmt);
|
||||
run_stmt(mysql, stmt,(uint32_t)mt_rand());
|
||||
created++;
|
||||
executed++;
|
||||
local_stmts->erase(a->statement_id);
|
||||
}
|
||||
} else { // no prepared statement was found in global
|
||||
stmt = mysql_stmt_init(mysql);
|
||||
if (!stmt) {
|
||||
fprintf(stderr, " mysql_stmt_init(), out of memory\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
/* blocking
|
||||
if (mysql_stmt_prepare(stmt, buff, bl)) { // the prepared statement is created
|
||||
fprintf(stderr, " mysql_stmt_prepare(), failed: %s\n" , mysql_stmt_error(stmt));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
*/
|
||||
async_exit_status=mysql_stmt_prepare_start(&ret_int, stmt, buff, bl);
|
||||
while (async_exit_status) {
|
||||
async_exit_status=wait_for_mysql(mysql, async_exit_status);
|
||||
async_exit_status=mysql_stmt_prepare_cont(&ret_int, stmt, async_exit_status);
|
||||
}
|
||||
if (ret_int) {
|
||||
fprintf(stderr, " mysql_stmt_prepare(), failed: %s\n" , mysql_stmt_error(stmt));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
MySQL_STMT_Global_info *stmt_info=NULL;
|
||||
stmt_info=GloMyStmt->add_prepared_statement(0,(char *)USER,(char *)SCHEMA,buff,bl,stmt);
|
||||
uint32_t stmid=stmt_info->statement_id;
|
||||
if (NUMPRO < 32)
|
||||
fprintf(stdout, "SERVER_statement_id=%lu , PROXY_statement_id=%u\n", stmt->stmt_id, stmid);
|
||||
local_stmts->insert(stmid,stmt);
|
||||
run_stmt(mysql, stmt,(uint32_t)mt_rand());
|
||||
created++;
|
||||
executed++;
|
||||
local_stmts->erase(stmid);
|
||||
}
|
||||
}
|
||||
fprintf(stdout, "Found %u , created %u and executed %u prepared statements in: ", founds, created, executed);
|
||||
}
|
||||
/*
|
||||
{
|
||||
// for comparison, we run also queries in TEXT protocol
|
||||
cpu_timer t;
|
||||
for (i=0; i<NUMPREP*LOOPS; i++) {
|
||||
sprintf(buff,"SELECT %u + %u",i,(uint32_t)mt_rand()%NUMPRO);
|
||||
bl=strlen(buff);
|
||||
int rc=mysql_real_query(mysql,buff,bl);
|
||||
if (rc) {
|
||||
fprintf(stderr, " mysql_real_query(), failed: %s\n" , mysql_error(mysql));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
MYSQL_RES *res=mysql_store_result(mysql);
|
||||
if (res==NULL) {
|
||||
fprintf(stderr, " mysql_store_result(), failed: %s\n" , mysql_error(mysql));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
mysql_free_result(res);
|
||||
}
|
||||
fprintf(stdout, "Executed %u queries in: ", i);
|
||||
}
|
||||
return 0;
|
||||
*/
|
||||
}
|
||||
|
||||
int main() {
|
||||
// initialize mysql
|
||||
mysql_library_init(0,NULL,NULL);
|
||||
|
||||
// create a new MySQL_STMT_Manager()
|
||||
GloMyStmt=new MySQL_STMT_Manager();
|
||||
GloThrData = (thread_data_t **)malloc(sizeof(thread_data_t *)*NTHREADS);
|
||||
|
||||
// starts N threads
|
||||
int i;
|
||||
for (i=0; i<NTHREADS; i++) {
|
||||
GloThrData[i]=(thread_data_t *)malloc(sizeof(thread_data_t));
|
||||
GloThrData[i]->thread = new std::thread(&mysql_thread,i);
|
||||
}
|
||||
// wait for the threads to complete
|
||||
for (i=0; i<NTHREADS; i++) {
|
||||
GloThrData[i]->thread->join();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
Binary file not shown.
@ -0,0 +1,79 @@
|
||||
#include "proxysql.h"
|
||||
#include "cpp.h"
|
||||
|
||||
// dummy copy of client1.cpp
|
||||
|
||||
#define QUERY1 "SELECT * from sbtest limit 10"
|
||||
MYSQL *mysql;
|
||||
MYSQL_STMT *stmt;
|
||||
uint32_t statement_id;
|
||||
uint16_t num_params;
|
||||
uint16_t num_columns;
|
||||
uint16_t warning_count;
|
||||
|
||||
int run_stmt(MYSQL_STMT *stmt, int int_data) {
|
||||
MYSQL_BIND bind[3];
|
||||
MYSQL_RES *prepare_meta_result;
|
||||
bind[0].buffer_type= MYSQL_TYPE_LONG;
|
||||
bind[0].buffer= (char *)&int_data;
|
||||
bind[0].is_null= 0;
|
||||
bind[0].length= 0;
|
||||
bind[1].buffer_type= MYSQL_TYPE_LONG;
|
||||
bind[1].buffer= (char *)&int_data;
|
||||
bind[1].is_null= 0;
|
||||
bind[1].length= 0;
|
||||
bind[2].buffer_type= MYSQL_TYPE_LONG;
|
||||
bind[2].buffer= (char *)&int_data;
|
||||
bind[2].is_null= 0;
|
||||
bind[2].length= 0;
|
||||
/*
|
||||
if (mysql_stmt_bind_param(stmt, bind)) {
|
||||
fprintf(stderr, " mysql_stmt_bind_param() failed\n");
|
||||
fprintf(stderr, " %s\n", mysql_stmt_error(stmt));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
*/
|
||||
prepare_meta_result = mysql_stmt_result_metadata(stmt); // FIXME: no error check
|
||||
if (mysql_stmt_execute(stmt)) {
|
||||
fprintf(stderr, " mysql_stmt_execute(), 1 failed\n");
|
||||
fprintf(stderr, " %s\n", mysql_stmt_error(stmt));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
// memset(bind, 0, sizeof(bind));
|
||||
if (mysql_stmt_store_result(stmt)) {
|
||||
fprintf(stderr, " mysql_stmt_store_result() failed\n");
|
||||
fprintf(stderr, " %s\n", mysql_stmt_error(stmt));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
mysql_free_result(prepare_meta_result);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int main() {
|
||||
std::mt19937 mt_rand(time(0));
|
||||
mysql = mysql_init(NULL);
|
||||
if (!mysql_real_connect(mysql,"127.0.0.1","msandbox","msandbox","sbtest",6033,NULL,0)) {
|
||||
//if (!mysql_real_connect(mysql,"127.0.0.1","root","","test",3306,NULL,0)) {
|
||||
fprintf(stderr, "Failed to connect to database: Error: %s\n", mysql_error(mysql));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
stmt = mysql_stmt_init(mysql);
|
||||
if (!stmt) {
|
||||
fprintf(stderr, " mysql_stmt_init(), out of memory\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (mysql_stmt_prepare(stmt, QUERY1, strlen(QUERY1))) {
|
||||
fprintf(stderr, " mysql_stmt_prepare(), failed: %d, %s\n" , mysql_errno(mysql), mysql_stmt_error(stmt));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
// param_count= mysql_stmt_param_count(stmt);
|
||||
// fprintf(stdout, " total parameters in Query1 : %d\n", param_count);
|
||||
statement_id=stmt->stmt_id;
|
||||
num_params=stmt->param_count;
|
||||
num_columns=stmt->field_count;
|
||||
warning_count=stmt->upsert_status.warning_count;
|
||||
fprintf(stdout, "statement_id=%d , columns=%d , params=%d , warnings=%d\n", statement_id, num_columns, num_params, warning_count);
|
||||
run_stmt(stmt,(uint32_t)mt_rand());
|
||||
return 0;
|
||||
}
|
||||
Loading…
Reference in new issue