driver/monitor_connection_context.cc (140 lines of code) (raw):
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License, version 2.0
// (GPLv2), as published by the Free Software Foundation, with the
// following additional permissions:
//
// This program is distributed with certain software that is licensed
// under separate terms, as designated in a particular file or component
// or in the license documentation. Without limiting your rights under
// the GPLv2, the authors of this program hereby grant you an additional
// permission to link the program and your derivative works with the
// separately licensed software that they have included with the program.
//
// Without limiting the foregoing grant of rights under the GPLv2 and
// additional permission as to separately licensed software, this
// program is also subject to the Universal FOSS Exception, version 1.0,
// a copy of which can be found along with its FAQ at
// http://oss.oracle.com/licenses/universal-foss-exception.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU General Public License, version 2.0, for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see
// http://www.gnu.org/licenses/gpl-2.0.html.
#include "monitor_connection_context.h"
#include "driver.h"
#include <algorithm>
#include <mutex>
MONITOR_CONNECTION_CONTEXT::MONITOR_CONNECTION_CONTEXT(DBC* connection_to_abort,
std::set<std::string> node_keys,
std::chrono::milliseconds failure_detection_time,
std::chrono::milliseconds failure_detection_interval,
int failure_detection_count,
bool enable_logging) : connection_to_abort{connection_to_abort},
node_keys{node_keys},
failure_detection_time{failure_detection_time},
failure_detection_interval{failure_detection_interval},
failure_detection_count{failure_detection_count},
failure_count{0},
node_unhealthy{false} {
if (enable_logging)
this->logger = init_log_file();
}
MONITOR_CONNECTION_CONTEXT::~MONITOR_CONNECTION_CONTEXT() {}
std::chrono::steady_clock::time_point MONITOR_CONNECTION_CONTEXT::get_start_monitor_time() {
return start_monitor_time;
}
void MONITOR_CONNECTION_CONTEXT::set_start_monitor_time(std::chrono::steady_clock::time_point time) {
start_monitor_time = time;
}
std::set<std::string> MONITOR_CONNECTION_CONTEXT::get_node_keys() {
return node_keys;
}
std::chrono::milliseconds MONITOR_CONNECTION_CONTEXT::get_failure_detection_time() {
return failure_detection_time;
}
std::chrono::milliseconds MONITOR_CONNECTION_CONTEXT::get_failure_detection_interval() {
return failure_detection_interval;
}
int MONITOR_CONNECTION_CONTEXT::get_failure_detection_count() {
return failure_detection_count;
}
int MONITOR_CONNECTION_CONTEXT::get_failure_count() {
return failure_count;
}
void MONITOR_CONNECTION_CONTEXT::set_failure_count(int count) {
failure_count = count;
}
void MONITOR_CONNECTION_CONTEXT::increment_failure_count() {
failure_count++;
}
void MONITOR_CONNECTION_CONTEXT::set_invalid_node_start_time(std::chrono::steady_clock::time_point time) {
invalid_node_start_time = time;
}
void MONITOR_CONNECTION_CONTEXT::reset_invalid_node_start_time() {
std::chrono::steady_clock::time_point timestamp_zero{};
invalid_node_start_time = timestamp_zero;
}
bool MONITOR_CONNECTION_CONTEXT::is_invalid_node_start_time_defined() {
std::chrono::steady_clock::time_point timestamp_zero{};
return invalid_node_start_time > timestamp_zero;
}
std::chrono::steady_clock::time_point MONITOR_CONNECTION_CONTEXT::get_invalid_node_start_time() {
return invalid_node_start_time;
}
bool MONITOR_CONNECTION_CONTEXT::is_node_unhealthy() {
return node_unhealthy;
}
void MONITOR_CONNECTION_CONTEXT::set_node_unhealthy(bool node) {
node_unhealthy = node;
}
bool MONITOR_CONNECTION_CONTEXT::is_active_context() {
return active_context.load();
}
void MONITOR_CONNECTION_CONTEXT::invalidate() {
active_context.store(false);
}
DBC* MONITOR_CONNECTION_CONTEXT::get_connection_to_abort() {
return connection_to_abort;
}
unsigned long MONITOR_CONNECTION_CONTEXT::get_dbc_id() {
return connection_to_abort ? connection_to_abort->id : 0;
}
// Update whether the connection is still valid if the total elapsed time has passed the grace period.
void MONITOR_CONNECTION_CONTEXT::update_connection_status(
std::chrono::steady_clock::time_point status_check_start_time,
std::chrono::steady_clock::time_point current_time,
bool is_valid) {
if (!is_active_context()) {
return;
}
auto total_elapsed_time = current_time - get_start_monitor_time();
if (total_elapsed_time > get_failure_detection_time()) {
set_connection_valid(is_valid, status_check_start_time, current_time);
}
}
// Set whether the connection to the server is still valid based on the monitoring settings.
void MONITOR_CONNECTION_CONTEXT::set_connection_valid(
bool connection_valid,
std::chrono::steady_clock::time_point status_check_start_time,
std::chrono::steady_clock::time_point current_time) {
const auto node_keys_str = build_node_keys_str();
if (!connection_valid) {
increment_failure_count();
if (!is_invalid_node_start_time_defined()) {
set_invalid_node_start_time(status_check_start_time);
}
const auto invalid_node_duration_ms = std::chrono::duration_cast<std::chrono::milliseconds>(current_time - get_invalid_node_start_time());
const auto max_invalid_node_duration = get_failure_detection_interval() * (std::max)(0, get_failure_detection_count());
if (invalid_node_duration_ms >= max_invalid_node_duration) {
MYLOG_TRACE(logger, get_dbc_id(), "[MONITOR_CONNECTION_CONTEXT] Node '%s' is *dead*.", node_keys_str.c_str());
set_node_unhealthy(true);
abort_connection();
return;
}
MYLOG_TRACE(
logger, get_dbc_id(),
"[MONITOR_CONNECTION_CONTEXT] Node '%s' is *not responding* (%d).", node_keys_str.c_str(), get_failure_count());
return;
}
set_failure_count(0);
reset_invalid_node_start_time();
set_node_unhealthy(false);
MYLOG_TRACE(logger, get_dbc_id(), "[MONITOR_CONNECTION_CONTEXT] Node '%s' is *alive*.", node_keys_str.c_str());
}
void MONITOR_CONNECTION_CONTEXT::abort_connection() {
std::lock_guard<std::mutex> lock(mutex_);
if ((!get_connection_to_abort()) || (!is_active_context())) {
return;
}
connection_to_abort->connection_proxy->close_socket();
}
std::string MONITOR_CONNECTION_CONTEXT::build_node_keys_str() {
if (node_keys.empty()) {
return "[]";
}
auto it = node_keys.begin();
std::string node_keys_str = '[' +(*it);
++it;
while (it != node_keys.end()) {
node_keys_str += ", " + *it;
++it;
}
node_keys_str += ']';
return node_keys_str;
}