|
|
|
|
@ -1741,42 +1741,49 @@ pair<int,pool_state_t> fetch_conn_stats(MYSQL* admin, const vector<uint32_t> hgs
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int wait_for_cond(MYSQL* mysql, const std::string& query, uint32_t timeout) {
|
|
|
|
|
int result = EXIT_FAILURE;
|
|
|
|
|
int check_cond(MYSQL* mysql, const string& q) {
|
|
|
|
|
diag("Checking condition '%s' in ('%s':%d)", q.c_str(), mysql->host, mysql->port);
|
|
|
|
|
|
|
|
|
|
auto start = std::chrono::system_clock::now();
|
|
|
|
|
std::chrono::duration<double> elapsed {};
|
|
|
|
|
int rc = mysql_query(mysql, q.c_str());
|
|
|
|
|
int res = 1;
|
|
|
|
|
|
|
|
|
|
while (elapsed.count() < timeout && result == EXIT_FAILURE) {
|
|
|
|
|
int rc = mysql_query(mysql, query.c_str());
|
|
|
|
|
fprintf(
|
|
|
|
|
stderr, "# %s: Waiting for condition '%s' in ('%s':%d)\n",
|
|
|
|
|
get_formatted_time().c_str(), query.c_str(), mysql->host, mysql->port
|
|
|
|
|
);
|
|
|
|
|
if (rc == 0) {
|
|
|
|
|
MYSQL_RES* myres = mysql_store_result(mysql);
|
|
|
|
|
|
|
|
|
|
if (rc == EXIT_SUCCESS) {
|
|
|
|
|
MYSQL_RES* myres = mysql_store_result(mysql);
|
|
|
|
|
if (myres) {
|
|
|
|
|
uint32_t field_num = mysql_num_fields(myres);
|
|
|
|
|
uint32_t row_num = mysql_num_rows(myres);
|
|
|
|
|
if (myres) {
|
|
|
|
|
uint32_t field_num = mysql_num_fields(myres);
|
|
|
|
|
uint32_t row_num = mysql_num_rows(myres);
|
|
|
|
|
|
|
|
|
|
if (field_num == 1 && row_num == 1) {
|
|
|
|
|
MYSQL_ROW row = mysql_fetch_row(myres);
|
|
|
|
|
if (field_num == 1 && row_num == 1) {
|
|
|
|
|
MYSQL_ROW myrow = mysql_fetch_row(myres);
|
|
|
|
|
|
|
|
|
|
if (row && strcasecmp("TRUE", row[0]) == 0) {
|
|
|
|
|
result = EXIT_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
if (myrow && strcasecmp("TRUE", myrow[0]) == 0) {
|
|
|
|
|
res = 0;
|
|
|
|
|
} else if (myrow && atoi(myrow[0]) >= 1) {
|
|
|
|
|
res = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
diag("Check failed with error '%s'", mysql_error(mysql));
|
|
|
|
|
res = -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mysql_free_result(myres);
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (result == EXIT_SUCCESS) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
diag("Condition query failed with error: ('%d','%s')", mysql_errno(mysql), mysql_error(mysql));
|
|
|
|
|
result = EXIT_FAILURE;
|
|
|
|
|
int wait_for_cond(MYSQL* mysql, const string& q, uint32_t to) {
|
|
|
|
|
diag("Waiting for condition '%s' in ('%s':%d)", q.c_str(), mysql->host, mysql->port);
|
|
|
|
|
|
|
|
|
|
int result = 1;
|
|
|
|
|
std::chrono::duration<double> elapsed {};
|
|
|
|
|
|
|
|
|
|
auto start = std::chrono::system_clock::now();
|
|
|
|
|
|
|
|
|
|
while (elapsed.count() < to && result == EXIT_FAILURE) {
|
|
|
|
|
result = check_cond(mysql, q);
|
|
|
|
|
|
|
|
|
|
if (result == 0 || result == -1) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -1789,6 +1796,74 @@ int wait_for_cond(MYSQL* mysql, const std::string& query, uint32_t timeout) {
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vector<check_res_t> wait_for_conds(MYSQL* mysql, const vector<string>& qs, uint32_t to) {
|
|
|
|
|
diag("Waiting multiple conditions in ('%s':%d):", mysql->host, mysql->port);
|
|
|
|
|
for (const string& q : qs) {
|
|
|
|
|
diag(" - cond: '%s'", q.c_str());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::chrono::duration<double> elapsed {};
|
|
|
|
|
|
|
|
|
|
vector<check_res_t> res {};
|
|
|
|
|
std::transform(qs.begin(), qs.end(), std::back_inserter(res),
|
|
|
|
|
[] (const string& q) {
|
|
|
|
|
return check_res_t { 1, q };
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
auto start = std::chrono::system_clock::now();
|
|
|
|
|
|
|
|
|
|
while (elapsed.count() < to) {
|
|
|
|
|
int chk_res = 0;
|
|
|
|
|
|
|
|
|
|
for (std::size_t i = 0; i < qs.size(); i++) {
|
|
|
|
|
chk_res = check_cond(mysql, qs[i]);
|
|
|
|
|
|
|
|
|
|
if (chk_res == -1) {
|
|
|
|
|
diag("Error during query. Aborting further checks");
|
|
|
|
|
res[i].first = -1;
|
|
|
|
|
break;
|
|
|
|
|
} else if (chk_res == 0) {
|
|
|
|
|
res[i].first = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int acc = std::accumulate(res.begin(), res.end(), size_t(0),
|
|
|
|
|
[] (size_t acc, const check_res_t& p) -> size_t {
|
|
|
|
|
if (p.first == 0) {
|
|
|
|
|
return acc + 1;
|
|
|
|
|
} else {
|
|
|
|
|
return acc;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (acc == qs.size() || chk_res == -1) {
|
|
|
|
|
break;
|
|
|
|
|
} else {
|
|
|
|
|
usleep(500 * 1000);
|
|
|
|
|
auto it_end = std::chrono::system_clock::now();
|
|
|
|
|
elapsed = it_end - start;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int proc_wait_checks(const vector<check_res_t>& chks) {
|
|
|
|
|
int res = 0;
|
|
|
|
|
|
|
|
|
|
for (const check_res_t& r : chks) {
|
|
|
|
|
if (r.first == -1) {
|
|
|
|
|
res = -1;
|
|
|
|
|
diag("Waiting check FAILED to execute '%s'", r.second.c_str());
|
|
|
|
|
} else if (r.first == 1) {
|
|
|
|
|
res = res == 0 ? 1 : res;
|
|
|
|
|
diag("Waiting check TIMEOUT '%s'", r.second.c_str());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void check_conn_count(MYSQL* admin, const string& conn_type, uint32_t conn_num, int32_t hg) {
|
|
|
|
|
const string hg_s { to_string(hg) };
|
|
|
|
|
const string conn_num_s { to_string(conn_num) };
|
|
|
|
|
@ -1858,8 +1933,67 @@ void check_query_count(MYSQL* admin, vector<uint32_t> queries, uint32_t hg) {
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const char* get_env_str(const char* envname, const char* envdefault) {
|
|
|
|
|
pair<int,vector<srv_addr_t>> fetch_cluster_nodes(MYSQL* admin, bool dump_fetch) {
|
|
|
|
|
int rc = mysql_query_t(admin, "SELECT hostname,port FROM proxysql_servers");
|
|
|
|
|
if (rc) { return { static_cast<int>(mysql_errno(admin)), {} }; }
|
|
|
|
|
|
|
|
|
|
MYSQL_RES* myres = mysql_store_result(admin);
|
|
|
|
|
if (myres == NULL) {
|
|
|
|
|
diag("Storing resultset failed error:%s", mysql_error(admin));
|
|
|
|
|
return { static_cast<int>(mysql_errno(admin)), {} };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (dump_fetch) {
|
|
|
|
|
const string res_table { dump_as_table(myres) };
|
|
|
|
|
diag("Dumping fetched cluster nodes:");
|
|
|
|
|
|
|
|
|
|
printf("%s", res_table.c_str());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vector<mysql_res_row> nodes_rows { extract_mysql_rows(myres) };
|
|
|
|
|
mysql_free_result(myres);
|
|
|
|
|
|
|
|
|
|
vector<srv_addr_t> nodes {};
|
|
|
|
|
std::transform(nodes_rows.begin(), nodes_rows.end(), std::back_inserter(nodes),
|
|
|
|
|
[] (const mysql_res_row& row) {
|
|
|
|
|
return srv_addr_t { row[0], std::atoi(row[1].c_str()) };
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
return { 0, nodes };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int check_nodes_sync(
|
|
|
|
|
const CommandLine& cl, const vector<srv_addr_t>& nodes, const string& check, uint32_t to
|
|
|
|
|
) {
|
|
|
|
|
for (const auto& node : nodes) {
|
|
|
|
|
MYSQL* admin = mysql_init(NULL);
|
|
|
|
|
|
|
|
|
|
if (
|
|
|
|
|
!mysql_real_connect(
|
|
|
|
|
admin, node.host.c_str(), cl.admin_username, cl.admin_password, NULL, node.port, NULL, 0
|
|
|
|
|
)
|
|
|
|
|
) {
|
|
|
|
|
diag("File %s, line %d, Error: %s\n", __FILE__, __LINE__, mysql_error(admin));
|
|
|
|
|
return EXIT_FAILURE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const vector<check_res_t> wres { wait_for_conds(admin, { check }, to) };
|
|
|
|
|
int node_sync = proc_wait_checks(wres);
|
|
|
|
|
|
|
|
|
|
if (node_sync != EXIT_SUCCESS) {
|
|
|
|
|
const string err { "Node '" + node.host + ":" + std::to_string(node.port) + "' sync timed out" };
|
|
|
|
|
diag("File %s, line %d, Error: %s\n", __FILE__, __LINE__, err.c_str());
|
|
|
|
|
return EXIT_FAILURE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mysql_close(admin);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return EXIT_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char* get_env_str(const char* envname, const char* envdefault) {
|
|
|
|
|
const char* envval = std::getenv(envname);
|
|
|
|
|
|
|
|
|
|
if (envval != NULL)
|
|
|
|
|
@ -1869,13 +2003,11 @@ const char* get_env_str(const char* envname, const char* envdefault) {
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
int get_env_int(const char* envname, int envdefault) {
|
|
|
|
|
|
|
|
|
|
const char* envval = std::getenv(envname);
|
|
|
|
|
int res = envdefault;
|
|
|
|
|
|
|
|
|
|
if (envval != NULL)
|
|
|
|
|
res = strtol(envval, NULL, 0);
|
|
|
|
|
// diag("%s: %s='%s' >>> %d", __FUNCTION__, envname, envval, res);
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
};
|
|
|
|
|
@ -1903,7 +2035,5 @@ bool get_env_bool(const char* envname, bool envdefault) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// diag("%s: %s='%s' >>> %d", __FUNCTION__, envname, envval, res);
|
|
|
|
|
|
|
|
|
|
return (bool) res;
|
|
|
|
|
};
|
|
|
|
|
|