From 6d0cccd64000ae35ce1e648020f852ba333a5ba2 Mon Sep 17 00:00:00 2001 From: David Reiss Date: Thu, 28 Feb 2008 21:20:12 +0000 Subject: [PATCH] Fail and retry logic for TSocketPool Summary: Replicating php logic: If opening fails enough times, mark server as down for some amount of time Reviewed By: aditya Test Plan: compiling thrift - any good test ideas? Revert: OK DiffCamp Revision: 8381 git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@665534 13f79535-47bb-0310-9956-ffa450edef68 --- lib/cpp/src/transport/TSocketPool.cpp | 71 ++++++++++++++++++++++----- lib/cpp/src/transport/TSocketPool.h | 33 ++++++++++++- 2 files changed, 91 insertions(+), 13 deletions(-) diff --git a/lib/cpp/src/transport/TSocketPool.cpp b/lib/cpp/src/transport/TSocketPool.cpp index 235d060e..af7303bd 100644 --- a/lib/cpp/src/transport/TSocketPool.cpp +++ b/lib/cpp/src/transport/TSocketPool.cpp @@ -13,6 +13,26 @@ namespace facebook { namespace thrift { namespace transport { using namespace std; +/** + * TSocketPoolServer implementation + * + * @author Akhil Wable + */ +TSocketPoolServer::TSocketPoolServer() + : host_(""), + port_(0), + lastFailTime_(0), + consecutiveFailures_(0) {} + +/** + * Constructor for TSocketPool server + */ +TSocketPoolServer::TSocketPoolServer(const std::string &host, int port) + : host_(host), + port_(port), + lastFailTime_(0), + consecutiveFailures_(0) {} + /** * TSocketPool implementation. * @@ -38,13 +58,15 @@ TSocketPool::TSocketPool(const vector &hosts, } TSocketPool::TSocketPool(const vector > servers) : TSocket(), - servers_(servers), numRetries_(1), retryInterval_(60), maxConsecutiveFailures_(1), randomize_(true), alwaysTryLast_(true) { + for (unsigned i = 0; i < servers.size(); ++i) { + addServer(servers[i].first, servers[i].second); + } } TSocketPool::TSocketPool(const string& host, int port) : TSocket(), @@ -62,7 +84,7 @@ TSocketPool::~TSocketPool() { } void TSocketPool::addServer(const string& host, int port) { - servers_.push_back(pair(host, port)); + servers_.push_back(TSocketPoolServer(host, port)); } void TSocketPool::setNumRetries(int numRetries) { @@ -92,20 +114,45 @@ void TSocketPool::open() { std::random_shuffle(servers_.begin(), servers_.end()); } - for (unsigned int i = 0; i < servers_.size(); ++i) { - host_ = servers_[i].first; - port_ = servers_[i].second; + unsigned int numServers = servers_.size(); + for (unsigned int i = 0; i < numServers; ++i) { + + TSocketPoolServer &server = servers_[i]; + bool retryIntervalPassed = (server.lastFailTime_ == 0); + bool isLastServer = alwaysTryLast_ ? (i == (numServers - 1)) : false; - for (int j = 0; j < numRetries_; ++j) { - try { - TSocket::open(); + if (server.lastFailTime_ > 0) { + // The server was marked as down, so check if enough time has elapsed to retry + int elapsedTime = time(NULL) - server.lastFailTime_; + if (elapsedTime > retryInterval_) { + retryIntervalPassed = true; + } + } - // success - return; - } catch (TException e) { - // connection failed + if (retryIntervalPassed || isLastServer) { + for (int j = 0; j < numRetries_; ++j) { + try { + TSocket::open(); + + // reset lastFailTime_ is required + if (server.lastFailTime_) { + server.lastFailTime_ = 0; + } + + // success + return; + } catch (TException e) { + // connection failed + } } } + + ++server.consecutiveFailures_; + if (server.consecutiveFailures_ > maxConsecutiveFailures_) { + // Mark server as down + server.consecutiveFailures_ = 0; + server.lastFailTime_ = time(NULL); + } } GlobalOutput("TSocketPool::open: all connections failed"); diff --git a/lib/cpp/src/transport/TSocketPool.h b/lib/cpp/src/transport/TSocketPool.h index 847f67e2..bed4cca0 100644 --- a/lib/cpp/src/transport/TSocketPool.h +++ b/lib/cpp/src/transport/TSocketPool.h @@ -12,6 +12,37 @@ namespace facebook { namespace thrift { namespace transport { + /** + * Class to hold server information for TSocketPool + * + * @author Akhil Wable + */ +class TSocketPoolServer { + + public: + /** + * Default constructor for server info + */ + TSocketPoolServer(); + + /** + * Constructor for TSocketPool server + */ + TSocketPoolServer(const std::string &host, int port); + + // Host name + std::string host_; + + // Port to connect on + int port_; + + // Last time connecting to this server failed + int lastFailTime_; + + // Number of consecutive times connecting to this server failed + int consecutiveFailures_; +}; + /** * TCP Socket implementation of the TTransport interface. * @@ -87,7 +118,7 @@ class TSocketPool : public TSocket { protected: /** List of servers to connect to */ - std::vector > servers_; + std::vector servers_; /** How many times to retry each host in connect */ int numRetries_; -- 2.17.1