From 6a3a824a18bc782788777c3a26a0d9d3f9dca33e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20S=C3=A1nchez=20Parra?= Date: Mon, 10 Oct 2022 21:02:27 +0200 Subject: [PATCH 1/9] Fix sequence id in EOF to OK packet conversion #3698 Fix invalid resultset when using query cache and mixing clients using and not using CLIENT_DEPRECATE_EOF. If a client connects to ProxySQL not using CLIENT_DEPRECATE_EOF and it caches a resultset, when a client using CLIENT_DEPRECATE_EOF executes the same query it will get an invalid resultset and the client will disconnect. The data in the resultset is correct, but proxysql skips a sequence id thus the client assumes it is corrupted. --- lib/Query_Cache.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/lib/Query_Cache.cpp b/lib/Query_Cache.cpp index de2dd7152..c20ac38a9 100644 --- a/lib/Query_Cache.cpp +++ b/lib/Query_Cache.cpp @@ -519,6 +519,18 @@ unsigned char* eof_to_ok_packet(QC_entry_t* entry) { memcpy(vp, it, 4); // ======================================= + // Decrement ids after the first EOF + unsigned char* dp = result + entry->column_eof_pkt_offset; + mysql_hdr decrement_hdr; + for (;;) { + memcpy(&decrement_hdr, dp, sizeof(mysql_hdr)); + decrement_hdr.pkt_id--; + memcpy(dp, &decrement_hdr, sizeof(mysql_hdr)); + dp += sizeof(mysql_hdr) + decrement_hdr.pkt_length; + if (dp >= vp) + break; + } + return result; } From ef3478c5c2ebb002a786f59c2b590804cb5ebf22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20S=C3=A1nchez=20Parra?= Date: Wed, 30 Nov 2022 10:24:59 +0100 Subject: [PATCH 2/9] Fix warnings and status position in EOF to OK package conversion If a client connects to ProxySQL not using CLIENT_DEPRECATE_EOF and it caches a resultset, when a client using CLIENT_DEPRECATE_EOF executes the same query it will get a resultset with wrong warnings and status flags. This is because warnings and status flags position must be swapped when converting an EOF packet to an OK packet. More info about warnings and status flags position in EOF and OK packets: https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_basic_eof_packet.html https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_basic_ok_packet.html --- lib/Query_Cache.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/lib/Query_Cache.cpp b/lib/Query_Cache.cpp index c20ac38a9..0b9163af2 100644 --- a/lib/Query_Cache.cpp +++ b/lib/Query_Cache.cpp @@ -515,8 +515,20 @@ unsigned char* eof_to_ok_packet(QC_entry_t* entry) { // Initialize affected_rows and last_insert_id to zero memset(vp, 0, 2); vp += 2; - // Copy the warning an status flags - memcpy(vp, it, 4); + // Extract warning flags and status from 'EOF_packet' + char* eof_packet = entry->value + entry->row_eof_pkt_offset; + eof_packet += sizeof(mysql_hdr); + // Skip the '0xFE EOF packet header' + eof_packet += 1; + uint16_t warnings; + memcpy(&warnings, eof_packet, sizeof(uint16_t)); + eof_packet += 2; + uint16_t status_flags; + memcpy(&status_flags, eof_packet, sizeof(uint16_t)); + // Copy warnings an status flags + memcpy(vp, &status_flags, sizeof(uint16_t)); + vp += 2; + memcpy(vp, &warnings, sizeof(uint16_t)); // ======================================= // Decrement ids after the first EOF From e4b349cf8e0fcb1d1d65d169d98e9a76cea1f0a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20S=C3=A1nchez=20Parra?= Date: Wed, 7 Dec 2022 10:26:10 +0100 Subject: [PATCH 3/9] Fix unaligned memory access in OK to EOF package conversion Fix unaligned memory access in ok_to_eof_packet() when copying warnings and status flags from OK to EOF packages. --- lib/Query_Cache.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/lib/Query_Cache.cpp b/lib/Query_Cache.cpp index 0b9163af2..5a70626c9 100644 --- a/lib/Query_Cache.cpp +++ b/lib/Query_Cache.cpp @@ -567,9 +567,11 @@ unsigned char* ok_to_eof_packet(QC_entry_t* entry) { ok_packet += sizeof(mysql_hdr); // Skip the 'OK packet header', 'affected_rows' and 'last_insert_id' ok_packet += 3; - uint16_t status_flags = *reinterpret_cast(ok_packet); + uint16_t status_flags; + memcpy(&status_flags, ok_packet, sizeof(uint16_t)); ok_packet += 2; - uint16_t warnings = *reinterpret_cast(ok_packet); + uint16_t warnings; + memcpy(&warnings, ok_packet, sizeof(uint16_t)); // Find the spot in which the first EOF needs to be placed it += sizeof(mysql_hdr); @@ -599,9 +601,9 @@ unsigned char* ok_to_eof_packet(QC_entry_t* entry) { // Write 'column_eof_packet' contents *vp = 0xfe; vp++; - *reinterpret_cast(vp) = warnings; + memcpy(vp, &warnings, sizeof(uint16_t)); vp += 2; - *reinterpret_cast(vp) = status_flags; + memcpy(vp, &status_flags, sizeof(uint16_t)); vp += 2; // Find the OK packet @@ -621,9 +623,9 @@ unsigned char* ok_to_eof_packet(QC_entry_t* entry) { *vp = 0xfe; vp++; - *reinterpret_cast(vp) = warnings; + memcpy(vp, &warnings, sizeof(uint16_t)); vp += 2; - *reinterpret_cast(vp) = status_flags; + memcpy(vp, &status_flags, sizeof(uint16_t)); break; } else { // Increment the package id by one due to 'column_eof_packet' From b5b3dfb4baf0ffd0b106ffb24ec3bcb38623c723 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20S=C3=A1nchez=20Parra?= Date: Thu, 1 Dec 2022 16:04:51 +0100 Subject: [PATCH 4/9] Fix offset in deprecate_eof_cache_t iterating through inserted values --- .../deprecate_eof_support/deprecate_eof_cache-t.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/tap/tests_with_deps/deprecate_eof_support/deprecate_eof_cache-t.cpp b/test/tap/tests_with_deps/deprecate_eof_support/deprecate_eof_cache-t.cpp index 7ca331d42..3517b49b7 100644 --- a/test/tap/tests_with_deps/deprecate_eof_support/deprecate_eof_cache-t.cpp +++ b/test/tap/tests_with_deps/deprecate_eof_support/deprecate_eof_cache-t.cpp @@ -141,9 +141,10 @@ int main(int argc, char** argv) { // Load query rules to runtime MYSQL_QUERY(proxy_admin, "LOAD MYSQL QUERY RULES TO RUNTIME"); - for (auto id = 0; id < c_operations; id++) { + for (auto i = 0; i < c_operations; i++) { int rnd_op = rand() % c_operations; + const auto id = i + 1; const std::string& t_select_query = queries[0]; std::string select_query {}; string_format(t_select_query, select_query, id); From 70eef57fdd3149d22e87243568531ee08c58d2ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20S=C3=A1nchez=20Parra?= Date: Thu, 1 Dec 2022 17:35:05 +0100 Subject: [PATCH 5/9] Refactor deprecate_eof_cache-t to compare against inserted values Use the vector which contains inserted data to validate received data from ProxySQL. --- .../deprecate_eof_cache-t.cpp | 54 ++++++++++++++++--- .../deprecate_eof_support/fwd_eof_query.cpp | 10 ++-- 2 files changed, 51 insertions(+), 13 deletions(-) diff --git a/test/tap/tests_with_deps/deprecate_eof_support/deprecate_eof_cache-t.cpp b/test/tap/tests_with_deps/deprecate_eof_support/deprecate_eof_cache-t.cpp index 3517b49b7..f13b80083 100644 --- a/test/tap/tests_with_deps/deprecate_eof_support/deprecate_eof_cache-t.cpp +++ b/test/tap/tests_with_deps/deprecate_eof_support/deprecate_eof_cache-t.cpp @@ -194,11 +194,30 @@ int main(int argc, char** argv) { return exit_status(); } + const nlohmann::json ok_query_res_json = nlohmann::json::parse(ok_query_res); + + const std::string ok_res_id = ok_query_res_json["Result"][0]["id"]; + ok( + ok_res_id == std::to_string(id), + "EOF to OK -> inserted id: %d // received id: %s", + id, + ok_res_id.c_str() + ); + + const std::string ok_res_c = ok_query_res_json["Result"][0]["c"]; + ok( + ok_res_c == stored_pairs[i].first, + "EOF to OK -> inserted c: %s // received c: %s", + stored_pairs[i].first.c_str(), + ok_res_c.c_str() + ); + + const std::string ok_res_pad = ok_query_res_json["Result"][0]["pad"]; ok( - eof_query_res == ok_query_res, - "EOF to OK: ['eof_query_res': %s] should match ['ok_query_res': %s]", - eof_query_res.c_str(), - ok_query_res.c_str() + ok_res_pad == stored_pairs[i].second, + "EOF to OK -> inserted pad: %s // received pad: %s", + stored_pairs[i].second.c_str(), + ok_res_pad.c_str() ); // Wait for invalidation of query_cache @@ -219,11 +238,30 @@ int main(int argc, char** argv) { return exit_status(); } + const nlohmann::json eof_query_res_json = nlohmann::json::parse(eof_query_res); + + const std::string eof_res_id = eof_query_res_json["Result"][0]["id"]; + ok( + eof_res_id == std::to_string(id), + "OK to EOF -> inserted id: %d // received id: %s", + id, + eof_res_id.c_str() + ); + + const std::string eof_res_c = eof_query_res_json["Result"][0]["c"]; + ok( + eof_res_c == stored_pairs[i].first, + "OK to EOF -> inserted c: %s // received c: %s", + stored_pairs[i].first.c_str(), + eof_res_c.c_str() + ); + + const std::string eof_res_pad = eof_query_res_json["Result"][0]["pad"]; ok( - eof_query_res == ok_query_res, - "OK to EOF: ['eof_query_res': %s] should match ['ok_query_res': %s]", - eof_query_res.c_str(), - ok_query_res.c_str() + eof_res_pad == stored_pairs[i].second, + "OK to EOF -> inserted pad: %s // received pad: %s", + stored_pairs[i].second.c_str(), + eof_res_pad.c_str() ); } diff --git a/test/tap/tests_with_deps/deprecate_eof_support/fwd_eof_query.cpp b/test/tap/tests_with_deps/deprecate_eof_support/fwd_eof_query.cpp index 8c232d6a6..230496d8a 100644 --- a/test/tap/tests_with_deps/deprecate_eof_support/fwd_eof_query.cpp +++ b/test/tap/tests_with_deps/deprecate_eof_support/fwd_eof_query.cpp @@ -114,14 +114,14 @@ int main(int argc, char** argv) { if (!mysql_real_connect(proxy, cl.host, cl.username, cl.password, NULL, cl.port, NULL, 0)) { std::string err_msg { "MySQL Error:" + std::string { mysql_error(proxy) }+ "" }; - std::cerr << "{ Code: Err, Result: " << err_msg << " }"; + std::cerr << "{ \"Code\": \"Err\", \"Result\": \"" << err_msg << "\" }"; return -1; } int query_res = mysql_query(proxy, query.c_str()); if (query_res != 0) { std::string err_msg { "MySQL Error:" + std::string { mysql_error(proxy) }+ "" }; - std::cerr << "{ Code: Err, Result: " << err_msg << " }"; + std::cerr << "{ \"Code\": \"Err\", \"Result\": \"" << err_msg << "\" }"; return -1; } @@ -131,19 +131,19 @@ int main(int argc, char** argv) { if (select_res != NULL) { json j_res {}; MySQL_result_to_JSON(select_res, j_res); - std::cout << "{ Code: OK, Result: " << j_res.dump() << " }"; + std::cout << "{ \"Code\": \"OK\", \"Result\": " << j_res.dump() << " }"; } else { std::string err_msg { "MySQL Error: " + std::string { mysql_error(proxy) }+ "" }; - std::cerr << "{ Code: Err, Result: " << err_msg << " }"; + std::cerr << "{ \"Code\": \"Err\", \"Result\": \"" << err_msg << "\" }"; res_code = -1; } mysql_free_result(select_res); } else { std::string err_msg { "MySQL Error:" + std::string { mysql_error(proxy) }+ "" }; - std::cerr << "{ Code: OK, Result: 0 }"; + std::cerr << "{ \"Code\": \"OK\", \"Result\": 0 }"; } mysql_close(proxy); From e73f3417f4d91583e01a58224ee11f6eafb7ab21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20S=C3=A1nchez=20Parra?= Date: Mon, 5 Dec 2022 11:41:20 +0100 Subject: [PATCH 6/9] Add tests for warnings and status flags for deprecate_eof_cache-t Tests if warnings and status flags from OK packets converted to EOF packets, and the other way around, are the same. --- .../deprecate_eof_cache-t.cpp | 42 ++++++++++++++++++- .../deprecate_eof_support/fwd_eof_query.cpp | 4 +- 2 files changed, 43 insertions(+), 3 deletions(-) diff --git a/test/tap/tests_with_deps/deprecate_eof_support/deprecate_eof_cache-t.cpp b/test/tap/tests_with_deps/deprecate_eof_support/deprecate_eof_cache-t.cpp index f13b80083..8d0bd6e48 100644 --- a/test/tap/tests_with_deps/deprecate_eof_support/deprecate_eof_cache-t.cpp +++ b/test/tap/tests_with_deps/deprecate_eof_support/deprecate_eof_cache-t.cpp @@ -194,7 +194,8 @@ int main(int argc, char** argv) { return exit_status(); } - const nlohmann::json ok_query_res_json = nlohmann::json::parse(ok_query_res); + nlohmann::json eof_query_res_json = nlohmann::json::parse(eof_query_res); + nlohmann::json ok_query_res_json = nlohmann::json::parse(ok_query_res); const std::string ok_res_id = ok_query_res_json["Result"][0]["id"]; ok( @@ -220,6 +221,24 @@ int main(int argc, char** argv) { ok_res_pad.c_str() ); + uint32_t eof_res_status = eof_query_res_json["Status"]; + uint32_t ok_res_status = ok_query_res_json["Status"]; + ok( + eof_res_status == ok_res_status, + "EOF to OK -> EOF received status: %d // OK received status: %d", + eof_res_status, + ok_res_status + ); + + uint32_t eof_res_warnings = eof_query_res_json["Warnings"]; + uint32_t ok_res_warnings = ok_query_res_json["Warnings"]; + ok( + eof_res_warnings == ok_res_warnings, + "EOF to OK -> EOF received warnings: %d // OK received warnings: %d", + eof_res_warnings, + ok_res_warnings + ); + // Wait for invalidation of query_cache usleep(110*1000); @@ -238,7 +257,8 @@ int main(int argc, char** argv) { return exit_status(); } - const nlohmann::json eof_query_res_json = nlohmann::json::parse(eof_query_res); + ok_query_res_json = nlohmann::json::parse(ok_query_res); + eof_query_res_json = nlohmann::json::parse(eof_query_res); const std::string eof_res_id = eof_query_res_json["Result"][0]["id"]; ok( @@ -263,6 +283,24 @@ int main(int argc, char** argv) { stored_pairs[i].second.c_str(), eof_res_pad.c_str() ); + + ok_res_status = ok_query_res_json["Status"]; + eof_res_status = eof_query_res_json["Status"]; + ok( + ok_res_status == eof_res_status, + "OK to EOF -> OK received status: %d // EOF received status: %d", + ok_res_status, + eof_res_status + ); + + ok_res_warnings = ok_query_res_json["Warnings"]; + eof_res_warnings = eof_query_res_json["Warnings"]; + ok( + ok_res_warnings == eof_res_warnings, + "OK to EOF -> OK received warnings: %d // EOF received warnings: %d", + ok_res_warnings, + eof_res_warnings + ); } // Delete new query cache rule diff --git a/test/tap/tests_with_deps/deprecate_eof_support/fwd_eof_query.cpp b/test/tap/tests_with_deps/deprecate_eof_support/fwd_eof_query.cpp index 230496d8a..82dd42913 100644 --- a/test/tap/tests_with_deps/deprecate_eof_support/fwd_eof_query.cpp +++ b/test/tap/tests_with_deps/deprecate_eof_support/fwd_eof_query.cpp @@ -131,7 +131,9 @@ int main(int argc, char** argv) { if (select_res != NULL) { json j_res {}; MySQL_result_to_JSON(select_res, j_res); - std::cout << "{ \"Code\": \"OK\", \"Result\": " << j_res.dump() << " }"; + std::cout << "{ \"Code\": \"OK\", \"Result\": " << j_res.dump() + << ", \"Status\": " << proxy->server_status + << ", \"Warnings\": " << mysql_warning_count(proxy) << " }"; } else { std::string err_msg { "MySQL Error: " + std::string { mysql_error(proxy) }+ "" From 740245d669a9591c5bde7254da046931ecb5678a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20S=C3=A1nchez=20Parra?= Date: Mon, 5 Dec 2022 17:31:16 +0100 Subject: [PATCH 7/9] Remove unused utils.h include from fwd_eof_query.cpp --- test/tap/tests_with_deps/deprecate_eof_support/fwd_eof_query.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/test/tap/tests_with_deps/deprecate_eof_support/fwd_eof_query.cpp b/test/tap/tests_with_deps/deprecate_eof_support/fwd_eof_query.cpp index 82dd42913..1c8b61613 100644 --- a/test/tap/tests_with_deps/deprecate_eof_support/fwd_eof_query.cpp +++ b/test/tap/tests_with_deps/deprecate_eof_support/fwd_eof_query.cpp @@ -12,7 +12,6 @@ #include "tap.h" #include "command_line.h" -#include "utils.h" #include "json.hpp" From 081ef669c9b01425c00998952d84295c0c6d08f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20S=C3=A1nchez=20Parra?= Date: Mon, 5 Dec 2022 17:32:23 +0100 Subject: [PATCH 8/9] Compile fwd_eof_query.cpp with libmysqlclient to test sequence id sanity libmariadbclient do not cares about sequence id sanity, so it can not be used to test it. --- test/tap/tests_with_deps/deprecate_eof_support/Makefile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/tap/tests_with_deps/deprecate_eof_support/Makefile b/test/tap/tests_with_deps/deprecate_eof_support/Makefile index f95c9ce81..6e7a3d819 100644 --- a/test/tap/tests_with_deps/deprecate_eof_support/Makefile +++ b/test/tap/tests_with_deps/deprecate_eof_support/Makefile @@ -62,12 +62,12 @@ eof_packet_mixed_queries-t: ok_packet_mixed_queries-t $(TESTS_DEPS) fwd_eof_query: fwd_eof_query.cpp $(TESTS_DEPS) $(CXX) -DNON_EOF_SUPPORT -DDEBUG fwd_eof_query.cpp $(OPT) -std=c++11 -I$(JSON_IDIR) -I$(TAP_LIBDIR) -I $(MARIADB_TEST_DEP)/include/ -I $(IDIR) -L$(TAP_LIBDIR) -L$(TAP_DEPS_LIBS) -L $(MARIADB_TEST_DEP)/libmariadb $(MYLIBS) -L$(SSL_LDIR) -ltap -ldl -o fwd_eof_query -DGITVERSION=\"$(GIT_VERSION)\" -fwd_eof_ok_query: fwd_eof_query.cpp $(TESTS_DEPS) - $(CXX) -DDEBUG fwd_eof_query.cpp $(INCLUDEDIRS) $(LDIRS) $(OPT) -std=c++11 -I$(TAP_LIBDIR) -L$(TAP_LIBDIR) $(MYLIBS) -L$(SSL_LDIR) -ltap -Wl,--no-as-needed -ldl -lpthread -o fwd_eof_ok_query -DGITVERSION=\"$(GIT_VERSION)\" +#fwd_eof_ok_query: fwd_eof_query.cpp $(TESTS_DEPS) +# $(CXX) -DDEBUG fwd_eof_query.cpp $(INCLUDEDIRS) $(LDIRS) $(OPT) -std=c++11 -I$(TAP_LIBDIR) -L$(TAP_LIBDIR) $(MYLIBS) -L$(SSL_LDIR) -ltap -Wl,--no-as-needed -ldl -lpthread -o fwd_eof_ok_query -DGITVERSION=\"$(GIT_VERSION)\" # NOTE: Compilation with 'libmysql' instead of 'libmariadb' client to confirm packet sequence id isn't check by 'libmariadb' -# fwd_eof_ok_query: fwd_eof_ok_query.cpp $(TAP_LIBDIR)/libtap.a -# $(CXX) -DDEBUG fwd_eof_ok_query.cpp $(OPT) -std=c++11 -I$(JSON_IDIR) -I$(TAP_LIBDIR) -I /usr/include/mysql/ -I $(IDIR) -L$(TAP_LIBDIR) -L$(TAP_DEPS_LIBS) -L /usr/lib/x86_64-linux-gnu/ -lmysqlclient -ltap -ldl -o fwd_eof_ok_query -DGITVERSION=\"$(GIT_VERSION)\" +fwd_eof_ok_query: fwd_eof_query.cpp $(TAP_LIBDIR)/libtap.a + $(CXX) -DDEBUG fwd_eof_query.cpp $(OPT) -std=c++11 -I$(JSON_IDIR) -I$(TAP_LIBDIR) -I /usr/include/mysql/ -I $(IDIR) -L$(TAP_LIBDIR) -L$(TAP_DEPS_LIBS) -L /usr/lib/x86_64-linux-gnu/ -lmysqlclient -ltap -ldl -o fwd_eof_ok_query -DGITVERSION=\"$(GIT_VERSION)\" deprecate_eof_cache-t: deprecate_eof_cache-t.cpp $(TESTS_DEPS) $(CXX) -DDEBUG deprecate_eof_cache-t.cpp $(OPT) -std=c++11 -I$(JSON_IDIR) -I$(TAP_LIBDIR) -I $(MARIADB_TEST_DEP)/include/ -I $(IDIR) -L$(TAP_LIBDIR) -L$(TAP_DEPS_LIBS) -L$(MARIADB_TEST_DEP)/libmariadb -L$(SSL_LDIR) -L$(PROXYLDIR) -ltap $(MYLIBS) -lproxysql -ldl -o deprecate_eof_cache-t -DGITVERSION=\"$(GIT_VERSION)\" From 8a8c45dada88e2af7fe0dcd3202d0dc8109219e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Jaramago=20Fern=C3=A1ndez?= Date: Thu, 8 Dec 2022 20:46:26 +0100 Subject: [PATCH 9/9] Fix potential race condition on test 'eof_fast_forward-t' --- .../deprecate_eof_support/eof_fast_forward-t.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/tap/tests_with_deps/deprecate_eof_support/eof_fast_forward-t.cpp b/test/tap/tests_with_deps/deprecate_eof_support/eof_fast_forward-t.cpp index 0e7928812..6931f811c 100644 --- a/test/tap/tests_with_deps/deprecate_eof_support/eof_fast_forward-t.cpp +++ b/test/tap/tests_with_deps/deprecate_eof_support/eof_fast_forward-t.cpp @@ -246,6 +246,9 @@ int main(int argc, char** argv) { MYSQL_QUERY(proxy, "/* create_new_connection=1 */ DO 1"); } + // Impose a timeout to avoid race conditions + wait_for_backend_conns(admin, "ConnFree", 50, 1); + // Check there are 'N' backend connections uint32_t cur_free_conns = 0; int get_conns_err = get_cur_backend_conns(admin, "ConnFree", cur_free_conns);