Skip to content

Commit 471ddfc

Browse files
authored
Merge pull request #5060 from sysown/v3.0_session_param_reset_connection
Fix Backend Connection Reset and Parameter Handling for RESET/SET TO DEFAULT
2 parents 2028605 + 249b3d8 commit 471ddfc

File tree

10 files changed

+225
-187
lines changed

10 files changed

+225
-187
lines changed

include/PgSQL_Connection.h

Lines changed: 46 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ class PgSQL_Conn_Param {
216216

217217
class PgSQL_Variable {
218218
public:
219-
char *value = (char*)"";
219+
char *value = nullptr;
220220
void fill_server_internal_session(nlohmann::json &j, int conn_num, int idx);
221221
void fill_client_internal_session(nlohmann::json &j, int idx);
222222
};
@@ -244,7 +244,7 @@ class PgSQL_Connection_userinfo {
244244

245245
class PgSQL_Connection {
246246
public:
247-
PgSQL_Connection();
247+
explicit PgSQL_Connection(bool is_client_conn);
248248
~PgSQL_Connection();
249249

250250
PG_ASYNC_ST handler(short event);
@@ -312,7 +312,7 @@ class PgSQL_Connection {
312312
if (error_info.severity == PGSQL_ERROR_SEVERITY::ERRSEVERITY_FATAL ||
313313
error_info.severity == PGSQL_ERROR_SEVERITY::ERRSEVERITY_ERROR ||
314314
error_info.severity == PGSQL_ERROR_SEVERITY::ERRSEVERITY_PANIC) {
315-
return true;
315+
return true;
316316
}
317317
return false;
318318
}
@@ -442,6 +442,42 @@ class PgSQL_Connection {
442442

443443
bool IsKeepMultiplexEnabledVariables(char* query_digest_text);
444444

445+
/**
446+
* @brief Retrieves startup parameter and it's hash
447+
*
448+
* This function tries to retrieve value and hash of startup paramters if present (provided in connection parameters).
449+
* If value is not found, it falls back to the thread-specific default variables.
450+
*
451+
* @param idx The index of startup parameter to retrieve.
452+
* @return The value and hash of startup parameter.
453+
*
454+
*/
455+
std::pair<const char*, uint32_t> get_startup_parameter_and_hash(enum pgsql_variable_name idx);
456+
457+
/**
458+
* @brief Copies tracked PgSQL session variables to startup parameters
459+
*
460+
* This function synchronizes the current tracked session variables (in `variables` and `var_hash`)
461+
* to the startup parameters arrays (`startup_parameters` and `startup_parameters_hash`). If `copy_only_critical_param`
462+
* is true, only the critical parameters (indices 0 to PGSQL_NAME_LAST_LOW_WM-1) are copied.
463+
* Otherwise, all tracked variables up to PGSQL_NAME_LAST_HIGH_WM are copied.
464+
*
465+
* @param copy_only_critical_param If true, only critical parameters are copied; otherwise, all tracked variables.
466+
*/
467+
void copy_pgsql_variables_to_startup_parameters(bool copy_only_critical_param);
468+
469+
/**
470+
* @brief Copies startup parameters to tracked PgSQL session variables.
471+
*
472+
* This function synchronizes the startup parameters arrays (`startup_parameters` and `startup_parameters_hash`)
473+
* to the tracked session variables (`variables` and `var_hash`). If `copy_only_critical_param` is true,
474+
* only the critical parameters (indices 0 to PGSQL_NAME_LAST_LOW_WM-1) are copied. Otherwise, all tracked
475+
* variables up to PGSQL_NAME_LAST_HIGH_WM are copied.
476+
*
477+
* @param copy_only_critical_param If true, only critical parameters are copied; otherwise, all tracked variables.
478+
*/
479+
void copy_startup_parameters_to_pgsql_variables(bool copy_only_critical_param);
480+
445481
struct {
446482
unsigned long length;
447483
char* ptr;
@@ -464,13 +500,16 @@ class PgSQL_Connection {
464500
unsigned long long pgconnpoll_put;
465501
} statuses;
466502

467-
PgSQL_Variable variables[PGSQL_NAME_LAST_HIGH_WM];
468-
uint32_t var_hash[PGSQL_NAME_LAST_HIGH_WM];
503+
std::array<PgSQL_Variable, PGSQL_NAME_LAST_HIGH_WM> variables = {};
504+
std::array<uint32_t, PGSQL_NAME_LAST_HIGH_WM> var_hash = {};
469505
// for now we store possibly missing variables in the lower range
470506
// we may need to fix that, but this will cost performance
471-
bool var_absent[PGSQL_NAME_LAST_HIGH_WM] = { false };
507+
std::array<bool, PGSQL_NAME_LAST_HIGH_WM> var_absent = {};
472508
std::vector<uint32_t> dynamic_variables_idx;
473509

510+
std::array<uint32_t, PGSQL_NAME_LAST_HIGH_WM> startup_parameters_hash = {};
511+
std::array<char*, PGSQL_NAME_LAST_HIGH_WM> startup_parameters = {};
512+
474513
/**
475514
* @brief Keeps tracks of the 'server_status'. Do not confuse with the 'server_status' from the
476515
* 'MYSQL' connection itself. This flag keeps track of the configured server status from the
@@ -499,7 +538,7 @@ class PgSQL_Connection {
499538
bool reusable;
500539
bool processing_multi_statement;
501540
bool multiplex_delayed;
502-
541+
bool is_client_connection; // true if this is a client connection, false if it is a server connection
503542

504543
PgSQL_SrvC *parent;
505544
PgSQL_Connection_userinfo* userinfo;

include/PgSQL_Session.h

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,6 @@ class PgSQL_Session : public Base_Session<PgSQL_Session, PgSQL_Data_Stream, PgSQ
369369
PtrSize_t pkt;
370370
std::string untracked_option_parameters;
371371
PgSQL_DateStyle_t current_datestyle = {};
372-
char* default_session_variables[PGSQL_NAME_LAST_HIGH_WM] = {};
373372

374373
#if 0
375374
// uint64_t
@@ -526,22 +525,6 @@ class PgSQL_Session : public Base_Session<PgSQL_Session, PgSQL_Data_Stream, PgSQ
526525
void detected_broken_connection(const char* file, unsigned int line, const char* func, const char* action, PgSQL_Connection* myconn, bool verbose = false);
527526
void generate_status_one_hostgroup(int hid, std::string& s);
528527
void set_previous_status_mode3(bool allow_execute = true);
529-
530-
void set_default_session_variable(enum pgsql_variable_name idx, const char* value);
531-
532-
/**
533-
* @brief Retrieves default session variable
534-
*
535-
* This function tries to retrieve value of default session variable if present (provided in connection parameters).
536-
* If value is not found, it falls back to the thread-specific default variables.
537-
*
538-
* @param idx The index of the session variable to retrieve.
539-
* @return The value of the session variable
540-
*
541-
*/
542-
const char* get_default_session_variable(enum pgsql_variable_name idx);
543-
544-
void reset_default_session_variable(enum pgsql_variable_name idx);
545528
};
546529

547530
#define PgSQL_KILL_QUERY 1

include/PgSQL_Thread.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -957,7 +957,7 @@ class PgSQL_Threads_Handler
957957
char* ldap_user_variable;
958958
char* add_ldap_user_comment;
959959
char* default_session_track_gtids;
960-
char* default_variables[PGSQL_NAME_LAST_HIGH_WM];
960+
char* default_variables[PGSQL_NAME_LAST_LOW_WM];
961961
char* firewall_whitelist_errormsg;
962962
#ifdef DEBUG
963963
bool session_debug;

include/proxysql_structs.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1192,7 +1192,7 @@ __thread int pgsql_thread___query_cache_soft_ttl_pct;
11921192
__thread int pgsql_thread___query_cache_handle_warnings;
11931193

11941194
__thread bool pgsql_thread___session_idle_show_processlist;
1195-
__thread char* pgsql_thread___default_variables[PGSQL_NAME_LAST_HIGH_WM];
1195+
__thread char* pgsql_thread___default_variables[PGSQL_NAME_LAST_LOW_WM];
11961196
__thread int pgsql_thread___handle_unknown_charset;
11971197
//---------------------------
11981198

@@ -1497,7 +1497,7 @@ extern __thread int pgsql_thread___query_cache_soft_ttl_pct;
14971497
extern __thread int pgsql_thread___query_cache_handle_warnings;
14981498

14991499
extern __thread bool pgsql_thread___session_idle_show_processlist;
1500-
extern __thread char* pgsql_thread___default_variables[PGSQL_NAME_LAST_HIGH_WM];
1500+
extern __thread char* pgsql_thread___default_variables[PGSQL_NAME_LAST_LOW_WM];
15011501
extern __thread int pgsql_thread___handle_unknown_charset;
15021502
//---------------------------
15031503

lib/Base_Thread.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ S Base_Thread::create_new_session_and_client_data_stream(int _fd) {
132132
sess->client_myds->myprot.dump_pkt = true;
133133
#endif
134134
if constexpr (std::is_same_v<T, PgSQL_Thread>) {
135-
PgSQL_Connection* myconn = new PgSQL_Connection();
135+
PgSQL_Connection* myconn = new PgSQL_Connection(true);
136136
sess->client_myds->attach_connection(myconn);
137137
} else if constexpr (std::is_same_v<T, MySQL_Thread>) {
138138
MySQL_Connection* myconn = new MySQL_Connection();

lib/PgSQL_Connection.cpp

Lines changed: 109 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -147,8 +147,9 @@ void print_backtrace(void);
147147

148148
#define NEXT_IMMEDIATE(new_st) do { async_state_machine = new_st; goto handler_again; } while (0)
149149

150-
PgSQL_Connection::PgSQL_Connection() {
150+
PgSQL_Connection::PgSQL_Connection(bool is_client_conn) {
151151
proxy_debug(PROXY_DEBUG_MYSQL_CONNPOOL, 4, "Creating new PgSQL_Connection %p\n", this);
152+
is_client_connection = is_client_conn;
152153
pgsql_conn = NULL;
153154
result_type = 0;
154155
pgsql_result = NULL;
@@ -179,10 +180,10 @@ PgSQL_Connection::PgSQL_Connection() {
179180
options.init_connect_sent = false;
180181
userinfo = new PgSQL_Connection_userinfo();
181182

182-
for (int i = 0; i < PGSQL_NAME_LAST_HIGH_WM; i++) {
183-
variables[i].value = NULL;
184-
var_hash[i] = 0;
185-
}
183+
//for (int i = 0; i < PGSQL_NAME_LAST_HIGH_WM; i++) {
184+
// variables[i].value = NULL;
185+
// var_hash[i] = 0;
186+
//}
186187

187188
new_result = true;
188189
is_copy_out = false;
@@ -215,13 +216,6 @@ PgSQL_Connection::~PgSQL_Connection() {
215216
delete query_result_reuse;
216217
query_result_reuse = NULL;
217218
}
218-
for (int i = 0; i < PGSQL_NAME_LAST_HIGH_WM; i++) {
219-
if (variables[i].value) {
220-
free(variables[i].value);
221-
variables[i].value = NULL;
222-
var_hash[i] = 0;
223-
}
224-
}
225219

226220
if (connected_host_details.hostname) {
227221
free(connected_host_details.hostname);
@@ -233,6 +227,22 @@ PgSQL_Connection::~PgSQL_Connection() {
233227
}
234228

235229
if (options.init_connect) free(options.init_connect);
230+
231+
for (int i = 0; i < PGSQL_NAME_LAST_HIGH_WM; ++i) {
232+
if (variables[i].value) {
233+
free(variables[i].value);
234+
variables[i].value = NULL;
235+
var_hash[i] = 0;
236+
}
237+
}
238+
239+
for (int i = 0; i < PGSQL_NAME_LAST_HIGH_WM; ++i) {
240+
if (startup_parameters[i]) {
241+
free(startup_parameters[i]);
242+
startup_parameters[i] = nullptr;
243+
startup_parameters_hash[i] = 0;
244+
}
245+
}
236246
}
237247

238248
void PgSQL_Connection::next_event(PG_ASYNC_ST new_st) {
@@ -756,44 +766,28 @@ void PgSQL_Connection::connect_start() {
756766
// charset validation is already done
757767
pgsql_variables.server_set_hash_and_value(myds->sess, PGSQL_CLIENT_ENCODING, client_charset, client_charset_hash);
758768

759-
std::vector<unsigned int> client_options;
760-
client_options.reserve(PGSQL_NAME_LAST_LOW_WM + myds->sess->client_myds->myconn->dynamic_variables_idx.size());
769+
// optimized way to set client parameters on backend connection when creating a new connection
770+
conninfo << "options='";
771+
// excluding client_encoding, which is already set above
772+
for (int idx = 1; idx < PGSQL_NAME_LAST_LOW_WM; idx++) {
773+
const char* value = pgsql_variables.client_get_value(myds->sess, idx);
774+
const char* escaped_str = escape_string_backslash_spaces(value);
775+
conninfo << "-c " << pgsql_tracked_variables[idx].set_variable_name << "=" << escaped_str << " ";
776+
if (escaped_str != value)
777+
free((char*)escaped_str);
761778

762-
// excluding PGSQL_CLIENT_ENCODING
763-
for (unsigned int idx = 1; idx < PGSQL_NAME_LAST_LOW_WM; idx++) {
764-
if (pgsql_variables.client_get_hash(myds->sess, idx) == 0) continue;
765-
client_options.push_back(idx);
779+
const uint32_t hash = pgsql_variables.client_get_hash(myds->sess, idx);
780+
pgsql_variables.server_set_hash_and_value(myds->sess, idx, value, hash);
766781
}
767782

768-
for (uint32_t idx : myds->sess->client_myds->myconn->dynamic_variables_idx) {
769-
assert(pgsql_variables.client_get_hash(myds->sess, idx));
770-
client_options.push_back(idx);
771-
}
772-
773-
if (client_options.empty() == false ||
774-
myds->sess->untracked_option_parameters.empty() == false) {
775-
776-
// optimized way to set client parameters on backend connection when creating a new connection
777-
conninfo << "options='";
778-
for (int idx : client_options) {
779-
const char* value = pgsql_variables.client_get_value(myds->sess, idx);
780-
const char* escaped_str = escape_string_backslash_spaces(value);
781-
conninfo << "-c " << pgsql_tracked_variables[idx].set_variable_name << "=" << escaped_str << " ";
782-
if (escaped_str != value)
783-
free((char*)escaped_str);
783+
myds->sess->mybe->server_myds->myconn->copy_pgsql_variables_to_startup_parameters(true);
784784

785-
const uint32_t hash = pgsql_variables.client_get_hash(myds->sess, idx);
786-
pgsql_variables.server_set_hash_and_value(myds->sess, idx, value, hash);
787-
}
788-
789-
myds->sess->mybe->server_myds->myconn->reorder_dynamic_variables_idx();
790-
791-
// if there are untracked parameters, the session should lock on the host group
792-
if (myds->sess->untracked_option_parameters.empty() == false) {
793-
conninfo << myds->sess->untracked_option_parameters;
794-
}
795-
conninfo << "'";
785+
// if there are untracked parameters, the session should lock on the host group
786+
if (myds->sess->untracked_option_parameters.empty() == false) {
787+
conninfo << myds->sess->untracked_option_parameters;
796788
}
789+
conninfo << "'";
790+
797791
}
798792

799793
/*conninfo << "postgres://";
@@ -1881,16 +1875,19 @@ void PgSQL_Connection::reset() {
18811875
reusable = true;
18821876
creation_time = monotonic_time();
18831877

1884-
for (int i = 0; i < PGSQL_NAME_LAST_HIGH_WM; i++) {
1878+
for (int i = (is_client_connection ? 0 : PGSQL_NAME_LAST_LOW_WM + 1);
1879+
i < PGSQL_NAME_LAST_HIGH_WM;
1880+
i++) {
18851881
var_hash[i] = 0;
18861882
if (variables[i].value) {
18871883
free(variables[i].value);
18881884
variables[i].value = NULL;
1889-
var_hash[i] = 0;
18901885
}
18911886
}
18921887
dynamic_variables_idx.clear();
18931888

1889+
if (!is_client_connection) copy_startup_parameters_to_pgsql_variables(/*copy_only_critical_param=*/true);
1890+
18941891
if (options.init_connect) {
18951892
free(options.init_connect);
18961893
options.init_connect = NULL;
@@ -2202,3 +2199,68 @@ void PgSQL_Connection::set_error_from_PQerrorMessage() {
22022199
const std::string_view& full_msg = !primary_msg.empty() ? primary_msg : lib_errmsg;
22032200
PgSQL_Error_Helper::fill_error_info(error_info, sqlstate.data(), full_msg.data(), severity.data());
22042201
}
2202+
2203+
std::pair<const char*, uint32_t> PgSQL_Connection::get_startup_parameter_and_hash(enum pgsql_variable_name idx) {
2204+
// within valid range?
2205+
assert(idx >= 0 && idx < PGSQL_NAME_LAST_HIGH_WM);
2206+
2207+
// Attempt to retrieve value from default startup parameters
2208+
if (startup_parameters_hash[idx] != 0) {
2209+
assert(startup_parameters[idx]);
2210+
return { startup_parameters[idx], startup_parameters_hash[idx] };
2211+
}
2212+
assert(!(idx < PGSQL_NAME_LAST_LOW_WM));
2213+
return { "", 0};
2214+
}
2215+
2216+
void PgSQL_Connection::copy_pgsql_variables_to_startup_parameters(bool copy_only_critical_param) {
2217+
2218+
//memcpy(startup_parameters_hash, var_hash, sizeof(uint32_t) * PGSQL_NAME_LAST_LOW_WM);
2219+
for (int i = 0; i < PGSQL_NAME_LAST_LOW_WM; ++i) {
2220+
assert(var_hash[i]);
2221+
assert(variables[i].value);
2222+
startup_parameters_hash[i] = var_hash[i];
2223+
free(startup_parameters[i]);
2224+
startup_parameters[i] = strdup(variables[i].value);
2225+
}
2226+
2227+
if (copy_only_critical_param) return;
2228+
2229+
for (int i = PGSQL_NAME_LAST_LOW_WM + 1; i < PGSQL_NAME_LAST_HIGH_WM; i++) {
2230+
if (var_hash[i] != 0) {
2231+
startup_parameters_hash[i] = var_hash[i];
2232+
free(startup_parameters[i]);
2233+
startup_parameters[i] = strdup(variables[i].value);
2234+
} else {
2235+
startup_parameters_hash[i] = 0;
2236+
free(startup_parameters[i]);
2237+
startup_parameters[i] = nullptr;
2238+
}
2239+
}
2240+
}
2241+
2242+
void PgSQL_Connection::copy_startup_parameters_to_pgsql_variables(bool copy_only_critical_param) {
2243+
2244+
//memcpy(var_hash, startup_parameters_hash, sizeof(uint32_t) * PGSQL_NAME_LAST_LOW_WM);
2245+
for (int i = 0; i < PGSQL_NAME_LAST_LOW_WM; i++) {
2246+
assert(startup_parameters_hash[i]);
2247+
assert(startup_parameters[i]);
2248+
var_hash[i] = startup_parameters_hash[i];
2249+
free(variables[i].value);
2250+
variables[i].value = strdup(startup_parameters[i]);
2251+
}
2252+
2253+
if (copy_only_critical_param) return;
2254+
2255+
for (int i = PGSQL_NAME_LAST_LOW_WM + 1; i < PGSQL_NAME_LAST_HIGH_WM; i++) {
2256+
if (startup_parameters_hash[i]) {
2257+
var_hash[i] = startup_parameters_hash[i];
2258+
free(variables[i].value);
2259+
variables[i].value = strdup(startup_parameters[i]);
2260+
} else {
2261+
var_hash[i] = 0;
2262+
free(variables[i].value);
2263+
variables[i].value = nullptr;
2264+
}
2265+
}
2266+
}

0 commit comments

Comments
 (0)