#ifndef __CLASS_MYSQL_THREAD_H #define __CLASS_MYSQL_THREAD_H #define ____CLASS_STANDARD_MYSQL_THREAD_H #include "proxysql.h" #include "cpp.h" #include #define MIN_POLL_LEN 8 #define MIN_POLL_DELETE_RATIO 8 #define MY_EPOLL_THREAD_MAXEVENTS 128 #define ADMIN_HOSTGROUP -2 #define STATS_HOSTGROUP -3 static unsigned int near_pow_2 (unsigned int n) { unsigned int i = 1; while (i < n) i <<= 1; return i ? i : n; } typedef struct __attribute__((aligned(CACHE_LINE_SIZE))) _conn_exchange_t { pthread_mutex_t mutex_idles; PtrArray *idle_mysql_sessions; pthread_mutex_t mutex_resumes; PtrArray *resume_mysql_sessions; } conn_exchange_t; class ProxySQL_Poll { private: void shrink() { unsigned int new_size=near_pow_2(len+1); fds=(struct pollfd *)realloc(fds,new_size*sizeof(struct pollfd)); myds=(MySQL_Data_Stream **)realloc(myds,new_size*sizeof(MySQL_Data_Stream *)); last_recv=(unsigned long long *)realloc(last_recv,new_size*sizeof(unsigned long long)); last_sent=(unsigned long long *)realloc(last_sent,new_size*sizeof(unsigned long long)); size=new_size; }; void expand(unsigned int more) { if ( (len+more) > size ) { unsigned int new_size=near_pow_2(len+more); fds=(struct pollfd *)realloc(fds,new_size*sizeof(struct pollfd)); myds=(MySQL_Data_Stream **)realloc(myds,new_size*sizeof(MySQL_Data_Stream *)); last_recv=(unsigned long long *)realloc(last_recv,new_size*sizeof(unsigned long long)); last_sent=(unsigned long long *)realloc(last_sent,new_size*sizeof(unsigned long long)); size=new_size; } }; public: unsigned int poll_timeout; unsigned long loops; StatCounters *loop_counters; unsigned int len; unsigned int size; struct pollfd *fds; MySQL_Data_Stream **myds; unsigned long long *last_recv; unsigned long long *last_sent; volatile int pending_listener_add; volatile int pending_listener_del; ProxySQL_Poll() { loop_counters=new StatCounters(15,10,false); poll_timeout=0; loops=0; len=0; pending_listener_add=0; pending_listener_del=0; size=MIN_POLL_LEN; fds=(struct pollfd *)malloc(size*sizeof(struct pollfd)); myds=(MySQL_Data_Stream **)malloc(size*sizeof(MySQL_Data_Stream *)); last_recv=(unsigned long long *)malloc(size*sizeof(unsigned long long)); last_sent=(unsigned long long *)malloc(size*sizeof(unsigned long long)); }; ~ProxySQL_Poll() { unsigned int i; for (i=0;imyds_type==MYDS_LISTENER) { delete myds[i]; } } free(myds); free(fds); free(last_recv); free(last_sent); delete loop_counters; }; void add(uint32_t _events, int _fd, MySQL_Data_Stream *_myds, unsigned long long sent_time) { if (len==size) { expand(1); } myds[len]=_myds; fds[len].fd=_fd; fds[len].events=_events; fds[len].revents=0; if (_myds) { _myds->mypolls=this; _myds->poll_fds_idx=len; // fix a serious bug } last_recv[len]=monotonic_time(); last_sent[len]=sent_time; len++; }; void remove_index_fast(unsigned int i) { if ((int)i==-1) return; myds[i]->poll_fds_idx=-1; // this prevents further delete if (i != (len-1)) { myds[i]=myds[len-1]; fds[i].fd=fds[len-1].fd; fds[i].events=fds[len-1].events; fds[i].revents=fds[len-1].revents; myds[i]->poll_fds_idx=i; // fix a serious bug last_recv[i]=last_recv[len-1]; last_sent[i]=last_sent[len-1]; } len--; if ( ( len>MIN_POLL_LEN ) && ( size > len*MIN_POLL_DELETE_RATIO ) ) { shrink(); } }; int find_index(int fd) { unsigned int i; for (i=0; i sessmap; protected: int nfds; public: ProxySQL_Poll mypolls; pthread_t thread_id; unsigned long long curtime; unsigned long long last_maintenance_time; PtrArray *mysql_sessions; PtrArray *idle_mysql_sessions; PtrArray *resume_mysql_sessions; conn_exchange_t myexchange; int pipefd[2]; int shutdown; bool epoll_thread; // status variables are per thread only // in this way, there is no need for atomic operation and there is no cache miss // when it is needed a total, all threads are checked struct { unsigned long long stmt_prepare; unsigned long long stmt_execute; unsigned long long stmt_close; unsigned long long queries; unsigned long long queries_slow; unsigned long long queries_backends_bytes_sent; unsigned long long queries_backends_bytes_recv; unsigned long long query_processor_time; unsigned long long backend_query_time; unsigned long long mysql_backend_buffers_bytes; unsigned long long mysql_frontend_buffers_bytes; unsigned long long mysql_session_internal_bytes; unsigned long long ConnPool_get_conn_immediate; unsigned long long ConnPool_get_conn_success; unsigned long long ConnPool_get_conn_failure; unsigned int active_transactions; } status_variables; rwlock_t thread_mutex; MySQL_Thread(); ~MySQL_Thread(); MySQL_Session * create_new_session_and_client_data_stream(int _fd); bool init(); void run(); void poll_listener_add(int sock); void poll_listener_del(int sock); void register_session(MySQL_Session*, bool up_start=true); void unregister_session(int); struct pollfd * get_pollfd(unsigned int i); bool process_data_on_data_stream(MySQL_Data_Stream *myds, unsigned int n); void process_all_sessions(); void refresh_variables(); void register_session_connection_handler(MySQL_Session *_sess, bool _new=false); void unregister_session_connection_handler(int idx, bool _new=false); //void myds_backend_set_failed_connect(MySQL_Data_Stream *myds, unsigned int n); //void myds_backend_pause_connect(MySQL_Data_Stream *myds); //void myds_backend_first_packet_after_connect(MySQL_Data_Stream *myds, unsigned int n); void listener_handle_new_connection(MySQL_Data_Stream *myds, unsigned int n); void Get_Memory_Stats(); MySQL_Connection * get_MyConn_local(unsigned int); void push_MyConn_local(MySQL_Connection *); void return_local_connections(); }; typedef MySQL_Thread * create_MySQL_Thread_t(); typedef void destroy_MySQL_Thread_t(MySQL_Thread *); class iface_info { public: char *iface; char *address; int port; int fd; iface_info(char *_i, char *_a, int p, int f) { iface=strdup(_i); address=strdup(_a); port=p; fd=f; } ~iface_info() { free(iface); free(address); close(fd); } }; class MySQL_Listeners_Manager { private: PtrArray *ifaces; public: MySQL_Listeners_Manager(); ~MySQL_Listeners_Manager(); int add(const char *iface, unsigned int num_threads, int **perthrsocks); //int add(const char *address, int port); int find_idx(const char *iface); int find_idx(const char *address, int port); iface_info * find_iface_from_fd(int fd); int get_fd(unsigned int idx); void del(unsigned int idx); }; class MySQL_Threads_Handler { private: int shutdown_; size_t stacksize; pthread_attr_t attr; rwlock_t rwlock; struct { int monitor_history; int monitor_connect_interval; int monitor_connect_timeout; int monitor_ping_interval; int monitor_ping_max_failures; int monitor_ping_timeout; int monitor_read_only_interval; int monitor_read_only_timeout; bool monitor_enabled; bool monitor_writer_is_also_reader; int monitor_replication_lag_interval; int monitor_replication_lag_timeout; int monitor_query_interval; int monitor_query_timeout; int monitor_slave_lag_when_null; char *monitor_username; char *monitor_password; int ping_interval_server_msec; int ping_timeout_server; int shun_on_failures; int shun_recovery_time_sec; int query_retries_on_failure; int connect_retries_on_failure; int connect_retries_delay; int connection_max_age_ms; int connect_timeout_server; int connect_timeout_server_max; int free_connections_pct; int session_idle_ms; bool session_idle_show_processlist; bool sessions_sort; char *default_schema; char *interfaces; char *server_version; uint8_t default_charset; bool servers_stats; bool commands_stats; bool query_digests; bool query_digests_lowercase; bool default_reconnect; bool have_compress; bool client_found_rows; bool multiplexing; // bool stmt_multiplexing; bool enforce_autocommit_on_reads; int max_allowed_packet; int max_transaction_time; int threshold_query_length; int threshold_resultset_size; int wait_timeout; int max_connections; int max_stmts_per_connection; int max_stmts_cache; int default_max_latency_ms; int default_query_delay; int default_query_timeout; int query_processor_iterations; int long_query_time; char *init_connect; #ifdef DEBUG bool session_debug; #endif /* DEBUG */ uint16_t server_capabilities; int poll_timeout; int poll_timeout_on_failure; char *eventslog_filename; int eventslog_filesize; // SSL related, proxy to server char * ssl_p2s_ca; char * ssl_p2s_cert; char * ssl_p2s_key; char * ssl_p2s_cipher; int query_cache_size_MB; } variables; PtrArray *bind_fds; MySQL_Listeners_Manager *MLM; public: unsigned int num_threads; proxysql_mysql_thread_t *mysql_threads; proxysql_mysql_thread_t *mysql_threads_idles; //rwlock_t rwlock_idles; //rwlock_t rwlock_resumes; //PtrArray *idle_mysql_sessions; //PtrArray *resume_mysql_sessions; //virtual const char *version() {return NULL;}; unsigned int get_global_version(); void wrlock(); void wrunlock(); void commit(); char *get_variable(char *name); bool set_variable(char *name, char *value); char **get_variables_list(); bool has_variable(const char * name); MySQL_Threads_Handler(); ~MySQL_Threads_Handler(); char *get_variable_string(char *name); uint8_t get_variable_uint8(char *name); uint16_t get_variable_uint16(char *name); int get_variable_int(char *name); void print_version(); void init(unsigned int num=0, size_t stack=0); proxysql_mysql_thread_t *create_thread(unsigned int tn, void *(*start_routine) (void *), bool); void shutdown_threads(); int listener_add(const char *iface); int listener_add(const char *address, int port); int listener_del(const char *iface); int listener_del(const char *address, int port); void start_listeners(); void stop_listeners(); void signal_all_threads(unsigned char _c=0); SQLite3_result * SQL3_Processlist(); SQLite3_result * SQL3_GlobalStatus(); bool kill_session(uint32_t _thread_session_id); unsigned long long get_total_stmt_prepare(); unsigned long long get_total_stmt_execute(); unsigned long long get_total_stmt_close(); unsigned long long get_total_queries(); unsigned long long get_slow_queries(); unsigned long long get_queries_backends_bytes_recv(); unsigned long long get_queries_backends_bytes_sent(); unsigned int get_active_transations(); unsigned int get_non_idle_client_connections(); unsigned long long get_query_processor_time(); unsigned long long get_backend_query_time(); unsigned long long get_mysql_backend_buffers_bytes(); unsigned long long get_mysql_frontend_buffers_bytes(); unsigned long long get_mysql_session_internal_bytes(); unsigned long long get_ConnPool_get_conn_immediate(); unsigned long long get_ConnPool_get_conn_success(); unsigned long long get_ConnPool_get_conn_failure(); iface_info *MLM_find_iface_from_fd(int fd) { return MLM->find_iface_from_fd(fd); } void Get_Memory_Stats(); }; #endif /* __CLASS_MYSQL_THREAD_H */