std::vector ClusterTopologyMonitor::open_any_conn_get_hosts()

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;
}