mirror of https://github.com/sysown/proxysql
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
145 lines
5.6 KiB
145 lines
5.6 KiB
#ifndef CLASS_PGSQL_PREPARED_STATEMENT_H
|
|
#define CLASS_PGSQL_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_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 PgSQL_STMT_Global_info {
|
|
private:
|
|
void compute_hash();
|
|
public:
|
|
pthread_rwlock_t rwlock_;
|
|
uint64_t digest;
|
|
PGSQL_QUERY_command PgQueryCmd;
|
|
char * digest_text;
|
|
uint64_t hash;
|
|
char *username;
|
|
char *schemaname;
|
|
char *query;
|
|
unsigned int query_length;
|
|
int ref_count_client;
|
|
int ref_count_server;
|
|
uint64_t statement_id;
|
|
char* first_comment;
|
|
uint64_t total_mem_usage;
|
|
PgSQL_Describe_Prepared_Info* stmt_metadata;
|
|
|
|
bool is_select_NOT_for_update;
|
|
PgSQL_STMT_Global_info(uint64_t id, char *u, char *s, char *q, unsigned int ql, char *fc, uint64_t _h);
|
|
void update_stmt_metadata(PgSQL_Describe_Prepared_Info** new_stmt_metadata);
|
|
~PgSQL_STMT_Global_info();
|
|
void calculate_mem_usage();
|
|
};
|
|
|
|
class PgSQL_STMTs_local_v14 {
|
|
private:
|
|
bool is_client_;
|
|
std::stack<uint32_t> free_backend_ids;
|
|
uint32_t local_max_stmt_id = 0;
|
|
|
|
public:
|
|
// this map associate client_stmt_id to global_stmt_id : this is used only for client connections
|
|
std::map<std::string, uint64_t> stmt_name_to_global_ids;
|
|
// this multimap associate global_stmt_id to client_stmt_id : this is used only for client connections
|
|
std::multimap<uint64_t, std::string> global_id_to_stmt_names;
|
|
|
|
// this map associate backend_stmt_id to global_stmt_id : this is used only for backend connections
|
|
std::map<uint32_t, uint64_t> backend_stmt_to_global_ids;
|
|
// this map associate global_stmt_id to backend_stmt_id : this is used only for backend connections
|
|
std::map<uint64_t, uint32_t> global_stmt_to_backend_ids;
|
|
|
|
PgSQL_Session *sess;
|
|
PgSQL_STMTs_local_v14(bool _ic) : is_client_(_ic), sess(NULL) { }
|
|
~PgSQL_STMTs_local_v14();
|
|
|
|
inline
|
|
void set_is_client(PgSQL_Session *_s) {
|
|
sess=_s;
|
|
is_client_ = true;
|
|
}
|
|
|
|
inline
|
|
bool is_client() { return is_client_; }
|
|
inline
|
|
unsigned int get_num_backend_stmts() { return backend_stmt_to_global_ids.size(); }
|
|
|
|
void backend_insert(uint64_t global_stmt_id, uint32_t backend_stmt_id);
|
|
void client_insert(uint64_t global_stmt_id, const std::string& client_stmt_name);
|
|
uint64_t compute_hash(char *user, char *schema, char *query, unsigned int query_length);
|
|
uint32_t generate_new_backend_stmt_id();
|
|
uint64_t find_global_id_from_stmt_name(const std::string& client_stmt_name);
|
|
uint32_t find_backend_stmt_id_from_global_id(uint64_t global_id);
|
|
bool client_close(const std::string& stmt_name);
|
|
};
|
|
|
|
|
|
class PgSQL_STMT_Manager_v14 {
|
|
private:
|
|
uint64_t next_statement_id;
|
|
uint64_t num_stmt_with_ref_client_count_zero;
|
|
uint64_t num_stmt_with_ref_server_count_zero;
|
|
pthread_rwlock_t rwlock_;
|
|
std::map<uint64_t, PgSQL_STMT_Global_info*> map_stmt_id_to_info; // map using statement id
|
|
std::map<uint64_t, PgSQL_STMT_Global_info*> map_stmt_hash_to_info; // map using hashes
|
|
std::stack<uint64_t> free_stmt_ids;
|
|
struct {
|
|
uint64_t c_unique;
|
|
uint64_t c_total;
|
|
uint64_t stmt_max_stmt_id;
|
|
uint64_t cached;
|
|
uint64_t s_unique;
|
|
uint64_t s_total;
|
|
} statuses;
|
|
time_t last_purge_time;
|
|
public:
|
|
PgSQL_STMT_Manager_v14();
|
|
~PgSQL_STMT_Manager_v14();
|
|
PgSQL_STMT_Global_info* find_prepared_statement_by_hash(uint64_t hash, bool lock=true);
|
|
PgSQL_STMT_Global_info* find_prepared_statement_by_stmt_id(uint64_t id, bool lock=true);
|
|
inline void rdlock() { pthread_rwlock_rdlock(&rwlock_); }
|
|
inline void wrlock() { pthread_rwlock_wrlock(&rwlock_); }
|
|
inline void unlock() { pthread_rwlock_unlock(&rwlock_); }
|
|
void ref_count_client(uint64_t _stmt, int _v, bool lock=true);
|
|
void ref_count_server(uint64_t _stmt, int _v, bool lock=true);
|
|
PgSQL_STMT_Global_info * add_prepared_statement(char *u, char *s, char *q, unsigned int ql, char *fc, bool lock=true);
|
|
void get_metrics(uint64_t *c_unique, uint64_t *c_total, uint64_t *stmt_max_stmt_id, uint64_t *cached, uint64_t *s_unique, uint64_t *s_total);
|
|
SQLite3_result* get_prepared_statements_global_infos();
|
|
void get_memory_usage(uint64_t& prep_stmt_metadata_mem_usage, uint64_t& prep_stmt_backend_mem_usage);
|
|
};
|
|
|
|
#endif /* CLASS_PGSQL_PREPARED_STATEMENT_H */
|