From f550cf1340047b65147be83df75251f640897291 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Canna=C3=B2?= Date: Mon, 29 May 2017 17:46:55 +0200 Subject: [PATCH] Speeding up user management LOAD MYSQL USERS TO RUNTIME is not faster Introduced LOAD MYSQL USER username TO RUNTIME --- include/proxysql_admin.h | 5 +- include/sqlite3db.h | 1 + lib/ProxySQL_Admin.cpp | 133 ++++++++++++++++++++++++++++++++++----- lib/sqlite3db.cpp | 38 +++++++++++ 4 files changed, 160 insertions(+), 17 deletions(-) diff --git a/include/proxysql_admin.h b/include/proxysql_admin.h index 63b72f11a..4a7745d4a 100644 --- a/include/proxysql_admin.h +++ b/include/proxysql_admin.h @@ -100,7 +100,7 @@ class ProxySQL_Admin { void __insert_or_replace_disktable_select_maintable(); void __attach_db(SQLite3DB *db1, SQLite3DB *db2, char *alias); - void __add_active_users(enum cred_username_type usertype); + void __add_active_users(enum cred_username_type usertype, char *user=NULL); void __delete_inactive_users(enum cred_username_type usertype); void add_admin_users(); void __refresh_users(); @@ -130,6 +130,9 @@ class ProxySQL_Admin { void *opt; void **re; } match_regexes; + void public_add_active_users(enum cred_username_type usertype, char *user=NULL) { + __add_active_users(usertype, user); + } ProxySQL_Admin(); ~ProxySQL_Admin(); SQLite3DB *admindb; // in memory diff --git a/include/sqlite3db.h b/include/sqlite3db.h index a9d971a03..234bbdfec 100644 --- a/include/sqlite3db.h +++ b/include/sqlite3db.h @@ -182,6 +182,7 @@ class SQLite3DB { bool execute(const char *); bool execute_statement(const char *, char **, int *, int *, SQLite3_result **); + bool execute_statement_raw(const char *, char **, int *, int *, sqlite3_stmt **); int return_one_int(const char *); int check_table_structure(char *table_name, char *table_def); bool build_table(char *table_name, char *table_def, bool dropit); diff --git a/lib/ProxySQL_Admin.cpp b/lib/ProxySQL_Admin.cpp index 4cf07ab2c..ba1484381 100644 --- a/lib/ProxySQL_Admin.cpp +++ b/lib/ProxySQL_Admin.cpp @@ -52,6 +52,28 @@ } while (rc!=SQLITE_DONE);\ } while (0) +void StringToHex(unsigned char *string, unsigned char *hexstring) { + unsigned char ch; + size_t i, j, l; + + l = strlen((char *)string); + for (i=0, j=0; i> 4; + if (ch <= 9) { + hexstring[j]= '0' + ch; + } else { + hexstring[j]= 'A' + ch - 10; + } + ch = string[i]; + ch = ch | 0x0F; + if (ch <= 9) { + hexstring[j+1]= '0' + ch; + } else { + hexstring[j+1]= 'A' + ch - 10; + } + } +} struct cpu_timer { @@ -80,16 +102,21 @@ char *s_strdup(char *s) { static char *sha1_pass_hex(char *sha1_pass) { // copied from MySQL_Protocol.cpp if (sha1_pass==NULL) return NULL; - char *buff=(char *)malloc(SHA_DIGEST_LENGTH*2+2); - buff[0]='*'; - buff[SHA_DIGEST_LENGTH*2+1]='\0'; - int i; - uint8_t a; - for (i=0;i16) && (!strncasecmp("LOAD MYSQL USER ", query_no_space, 16)) ) { + if (query_no_space_length>27) { + if (!strncasecmp(" TO RUNTIME", query_no_space+query_no_space_length-11, 11)) { + char *name=(char *)malloc(query_no_space_length-27+1); + strncpy(name,query_no_space+16,query_no_space_length-27); + name[query_no_space_length-27]=0; + int i=0; + int s=strlen(name); + bool legitname=true; + for (i=0; i= 'a' && c <= 'z') || + (c >= 'A' && c <= 'Z') || + (c >= '0' && c <= '9') || + ( (c == '-') || (c == '+') || (c == '_')) + ) { + v=true; + } + if (v==false) { + legitname=false; + } + } + if (legitname) { + proxy_info("Loading user %s\n", name); + SPA->send_MySQL_OK(&sess->client_myds->myprot, NULL); + SPA->public_add_active_users(USERNAME_BACKEND, name); + SPA->public_add_active_users(USERNAME_FRONTEND, name); + } else { + proxy_info("Tried to load invalid user %s\n", name); + char *s=(char *)"Invalid name %s"; + char *m=(char *)malloc(strlen(s)+strlen(name)+1); + sprintf(m,s,name); + SPA->send_MySQL_ERR(&sess->client_myds->myprot, m); + } + free(name); + return false; + } + } + } if ((query_no_space_length>17) && ( (!strncasecmp("SAVE MYSQL USERS ", query_no_space, 17)) || (!strncasecmp("LOAD MYSQL USERS ", query_no_space, 17))) ) { if ( @@ -3905,7 +3973,7 @@ void ProxySQL_Admin::send_MySQL_ERR(MySQL_Protocol *myprot, char *msg) { assert(myprot); MySQL_Data_Stream *myds=myprot->get_myds(); myds->DSS=STATE_QUERY_SENT_DS; - myprot->generate_pkt_ERR(true,NULL,NULL,1,1045,(char *)"#28000",msg); + myprot->generate_pkt_ERR(true,NULL,NULL,1,1045,(char *)"28000",msg); myds->DSS=STATE_SLEEP; } @@ -3930,20 +3998,44 @@ void ProxySQL_Admin::__delete_inactive_users(enum cred_username_type usertype) { free(query); } -void ProxySQL_Admin::__add_active_users(enum cred_username_type usertype) { +#define ADDUSER_STMT_RAW +void ProxySQL_Admin::__add_active_users(enum cred_username_type usertype, char *__user) { char *error=NULL; int cols=0; int affected_rows=0; +#ifdef ADDUSER_STMT_RAW + sqlite3_stmt *statement=NULL; +#else SQLite3_result *resultset=NULL; - char *str=(char *)"SELECT username,password,use_ssl,default_hostgroup,default_schema,schema_locked,transaction_persistent,fast_forward,max_connections FROM main.mysql_users WHERE %s=1 AND active=1 AND default_hostgroup>=0"; - char *query=(char *)malloc(strlen(str)+15); - sprintf(query,str,(usertype==USERNAME_BACKEND ? "backend" : "frontend")); +#endif + char *str=NULL; + char *query=NULL; + if (__user==NULL) { + str=(char *)"SELECT username,password,use_ssl,default_hostgroup,default_schema,schema_locked,transaction_persistent,fast_forward,max_connections FROM main.mysql_users WHERE %s=1 AND active=1 AND default_hostgroup>=0"; + query=(char *)malloc(strlen(str)+15); + sprintf(query,str,(usertype==USERNAME_BACKEND ? "backend" : "frontend")); + } else { + str=(char *)"SELECT username,password,use_ssl,default_hostgroup,default_schema,schema_locked,transaction_persistent,fast_forward,max_connections FROM main.mysql_users WHERE %s=1 AND active=1 AND default_hostgroup>=0 AND username='%s'"; + query=(char *)malloc(strlen(str)+strlen(__user)+15); + sprintf(query,str,(usertype==USERNAME_BACKEND ? "backend" : "frontend"),__user); + } +#ifdef ADDUSER_STMT_RAW + admindb->execute_statement_raw(query, &error , &cols , &affected_rows , &statement); +#else admindb->execute_statement(query, &error , &cols , &affected_rows , &resultset); +#endif if (error) { proxy_error("Error on %s : %s\n", query, error); } else { +#ifdef ADDUSER_STMT_RAW + int rc; + while ((rc=sqlite3_step(statement))==SQLITE_ROW) { + SQLite3_row *r=new SQLite3_row(cols); + r->add_fields(statement); +#else for (std::vector::iterator it = resultset->rows.begin() ; it != resultset->rows.end(); ++it) { - SQLite3_row *r=*it; + SQLite3_row *r=*it; +#endif char *password=NULL; if (variables.hash_passwords) { // We must use hashed password. See issue #676 // Admin needs to hash the password @@ -3987,9 +4079,18 @@ void ProxySQL_Admin::__add_active_users(enum cred_username_type usertype) { if (variables.hash_passwords) { free(password); // because we always generate a new string } +#ifdef ADDUSER_STMT_RAW + delete r; +#endif } } +#ifdef ADDUSER_STMT_RAW + if (statement) { + sqlite3_finalize(statement); + } +#else if (resultset) delete resultset; +#endif free(query); } diff --git a/lib/sqlite3db.cpp b/lib/sqlite3db.cpp index 7bcafd619..2bf522604 100644 --- a/lib/sqlite3db.cpp +++ b/lib/sqlite3db.cpp @@ -109,6 +109,44 @@ __exit_execute_statement: return ret; } +bool SQLite3DB::execute_statement_raw(const char *str, char **error, int *cols, int *affected_rows, sqlite3_stmt **statement) { + int rc; + //sqlite3_stmt *statement=NULL; + *error=NULL; + bool ret=false; + VALGRIND_DISABLE_ERROR_REPORTING; + if(sqlite3_prepare_v2(db, str, -1, statement, 0) != SQLITE_OK) { + *error=strdup(sqlite3_errmsg(db)); + goto __exit_execute_statement; + } + VALGRIND_ENABLE_ERROR_REPORTING; + *cols = sqlite3_column_count(*statement); + if (*cols==0) { // not a SELECT + //*resultset=NULL; + do { + rc=sqlite3_step(*statement); + if (rc==SQLITE_LOCKED) { // the execution of the prepared statement failed because locked + usleep(USLEEP_SQLITE_LOCKED); + } + } while (rc==SQLITE_LOCKED); + if (rc==SQLITE_DONE) { + *affected_rows=sqlite3_changes(db); + ret=true; + } else { + *error=strdup(sqlite3_errmsg(db)); + goto __exit_execute_statement; + } + } else { + *affected_rows=0; + //*resultset=new SQLite3_result(statement); + ret=true; + } +__exit_execute_statement: + // NOTE: the caller MUST call sqlite3_finalize() + //sqlite3_finalize(statement); + return ret; +} + int SQLite3DB::return_one_int(const char *str) { char *error=NULL; int cols=0;