in src/failover/cluster_topology_monitor.cc [249:303]
std::vector<HostInfo> ClusterTopologyMonitor::open_any_conn_get_hosts() {
SQLRETURN rc;
bool thread_writer_verified = false;
auto* conn_cstr = AS_SQLTCHAR(conn_str_.c_str());
if (!main_hdbc_) {
SQLHDBC local_hdbc;
// open a new connection
SQLSetEnvAttr(henv_, SQL_ATTR_ODBC_VERSION, reinterpret_cast<SQLPOINTER>(SQL_OV_ODBC3), 0);
SQLAllocHandle(SQL_HANDLE_DBC, henv_, &local_hdbc);
rc = SQLDriverConnect(local_hdbc, nullptr, conn_cstr, SQL_NTS,
nullptr, 0, nullptr, SQL_DRIVER_NOPROMPT);
if (!odbc_helper_->CheckResult(rc, std::string("ClusterTopologyMonitor failed to open connection for clusterId: ") + cluster_id_, local_hdbc, SQL_HANDLE_DBC)) {
SQLDisconnect(local_hdbc);
SQLFreeHandle(SQL_HANDLE_DBC, local_hdbc);
return std::vector<HostInfo>();
}
// Check if another thread already set HDBC
std::lock_guard<std::mutex> hdbc_lock(hdbc_mutex_);
if (!main_hdbc_) {
main_hdbc_ = std::make_shared<SQLHDBC>(local_hdbc);
std::string writer_id = query_helper_->GetWriterId(local_hdbc);
if (!writer_id.empty()) {
thread_writer_verified = true;
is_writer_connection_.store(true);
// TODO(yuenhcol), double lock makes this complicated & complex, need to come back to refactor
std::lock_guard host_info_lock(node_threads_writer_hdbc_mutex_);
main_writer_host_info_ = std::make_shared<HostInfo>(query_helper_->CreateHost(AS_SQLTCHAR(writer_id.c_str()), true, 0, 0));
}
} else {
// Connection already set, close local HDBC
SQLDisconnect(local_hdbc);
SQLFreeHandle(SQL_HANDLE_DBC, local_hdbc);
}
}
std::vector<HostInfo> hosts = FetchTopologyUpdateCache(reinterpret_cast<SQLHDBC>(*(main_hdbc_.get())));
if (thread_writer_verified) {
// Writer verified at initial connection & failovers but want to ignore new topology requests after failover
// The first writer will be able to set from epoch to a proper end time
std::chrono::steady_clock::time_point expected = std::chrono::steady_clock::time_point{}; // Epoch
std::chrono::steady_clock::time_point new_time =
std::chrono::steady_clock::time_point(std::chrono::high_resolution_clock::now().time_since_epoch()) +
std::chrono::milliseconds(ignore_topology_request_ms_);
ignore_topology_request_end_ms_.compare_exchange_strong(expected, new_time);
}
if (hosts.empty()) {
// No topology, close connection
std::lock_guard hdbc_lock(hdbc_mutex_);
dbc_clean_up(main_hdbc_);
is_writer_connection_.store(false);
}
return hosts;
}