blob: 85c2a61c6f62cca6607e26c036c857cccd19be25 [file] [log] [blame]
jsobele02e4242007-05-08 17:51:49 +00001// Copyright (c) 2007- Facebook
2// Distributed under the Thrift Software License
3//
4// See accompanying file LICENSE or visit the Thrift site at:
5// http://developers.facebook.com/thrift/
6
7#include <algorithm>
8#include <iostream>
9
10#include "TSocketPool.h"
11
T Jake Lucianib5e62212009-01-31 22:36:20 +000012namespace apache { namespace thrift { namespace transport {
jsobele02e4242007-05-08 17:51:49 +000013
14using namespace std;
15
David Reiss8f3bce42008-03-18 18:21:52 +000016using boost::shared_ptr;
17
jsobele02e4242007-05-08 17:51:49 +000018/**
David Reiss6d0cccd2008-02-28 21:20:12 +000019 * TSocketPoolServer implementation
20 *
David Reiss6d0cccd2008-02-28 21:20:12 +000021 */
22TSocketPoolServer::TSocketPoolServer()
23 : host_(""),
24 port_(0),
David Reiss1997f102008-04-29 00:29:41 +000025 socket_(-1),
David Reiss6d0cccd2008-02-28 21:20:12 +000026 lastFailTime_(0),
27 consecutiveFailures_(0) {}
28
29/**
30 * Constructor for TSocketPool server
31 */
David Reiss8f3bce42008-03-18 18:21:52 +000032TSocketPoolServer::TSocketPoolServer(const string &host, int port)
David Reiss6d0cccd2008-02-28 21:20:12 +000033 : host_(host),
34 port_(port),
David Reiss1997f102008-04-29 00:29:41 +000035 socket_(-1),
David Reiss6d0cccd2008-02-28 21:20:12 +000036 lastFailTime_(0),
37 consecutiveFailures_(0) {}
38
39/**
jsobele02e4242007-05-08 17:51:49 +000040 * TSocketPool implementation.
41 *
jsobele02e4242007-05-08 17:51:49 +000042 */
43
David Reiss8f3bce42008-03-18 18:21:52 +000044TSocketPool::TSocketPool() : TSocket(),
45 numRetries_(1),
46 retryInterval_(60),
47 maxConsecutiveFailures_(1),
48 randomize_(true),
49 alwaysTryLast_(true) {
50}
51
jsobele02e4242007-05-08 17:51:49 +000052TSocketPool::TSocketPool(const vector<string> &hosts,
53 const vector<int> &ports) : TSocket(),
54 numRetries_(1),
55 retryInterval_(60),
56 maxConsecutiveFailures_(1),
57 randomize_(true),
58 alwaysTryLast_(true)
59{
60 if (hosts.size() != ports.size()) {
boz6ded7752007-06-05 22:41:18 +000061 GlobalOutput("TSocketPool::TSocketPool: hosts.size != ports.size");
jsobele02e4242007-05-08 17:51:49 +000062 throw TTransportException(TTransportException::BAD_ARGS);
63 }
64
65 for (unsigned int i = 0; i < hosts.size(); ++i) {
dweatherfordd1372822007-10-09 22:57:23 +000066 addServer(hosts[i], ports[i]);
jsobele02e4242007-05-08 17:51:49 +000067 }
68}
69
David Reiss8f3bce42008-03-18 18:21:52 +000070TSocketPool::TSocketPool(const vector<pair<string, int> >& servers) : TSocket(),
jsobele02e4242007-05-08 17:51:49 +000071 numRetries_(1),
72 retryInterval_(60),
73 maxConsecutiveFailures_(1),
74 randomize_(true),
75 alwaysTryLast_(true)
76{
David Reiss6d0cccd2008-02-28 21:20:12 +000077 for (unsigned i = 0; i < servers.size(); ++i) {
78 addServer(servers[i].first, servers[i].second);
79 }
jsobele02e4242007-05-08 17:51:49 +000080}
81
David Reiss8f3bce42008-03-18 18:21:52 +000082TSocketPool::TSocketPool(const vector< shared_ptr<TSocketPoolServer> >& servers) : TSocket(),
David Reiss907ad762008-03-02 00:25:58 +000083 servers_(servers),
84 numRetries_(1),
85 retryInterval_(60),
86 maxConsecutiveFailures_(1),
87 randomize_(true),
88 alwaysTryLast_(true)
89{
90}
91
dweatherfordd1372822007-10-09 22:57:23 +000092TSocketPool::TSocketPool(const string& host, int port) : TSocket(),
93 numRetries_(1),
94 retryInterval_(60),
95 maxConsecutiveFailures_(1),
96 randomize_(true),
97 alwaysTryLast_(true)
98{
99 addServer(host, port);
100}
101
jsobele02e4242007-05-08 17:51:49 +0000102TSocketPool::~TSocketPool() {
David Reiss1997f102008-04-29 00:29:41 +0000103 vector< shared_ptr<TSocketPoolServer> >::const_iterator iter = servers_.begin();
104 vector< shared_ptr<TSocketPoolServer> >::const_iterator iterEnd = servers_.end();
105 for (; iter != iterEnd; ++iter) {
106 setCurrentServer(*iter);
107 TSocketPool::close();
108 }
jsobele02e4242007-05-08 17:51:49 +0000109}
110
dweatherfordd1372822007-10-09 22:57:23 +0000111void TSocketPool::addServer(const string& host, int port) {
David Reiss8f3bce42008-03-18 18:21:52 +0000112 servers_.push_back(shared_ptr<TSocketPoolServer>(new TSocketPoolServer(host, port)));
dweatherfordd1372822007-10-09 22:57:23 +0000113}
114
David Reiss8f3bce42008-03-18 18:21:52 +0000115void TSocketPool::setServers(const vector< shared_ptr<TSocketPoolServer> >& servers) {
116 servers_ = servers;
117}
118
119void TSocketPool::getServers(vector< shared_ptr<TSocketPoolServer> >& servers) {
120 servers = servers_;
David Reiss907ad762008-03-02 00:25:58 +0000121}
122
jsobele02e4242007-05-08 17:51:49 +0000123void TSocketPool::setNumRetries(int numRetries) {
124 numRetries_ = numRetries;
125}
126
127void TSocketPool::setRetryInterval(int retryInterval) {
128 retryInterval_ = retryInterval;
129}
130
131
132void TSocketPool::setMaxConsecutiveFailures(int maxConsecutiveFailures) {
133 maxConsecutiveFailures_ = maxConsecutiveFailures;
134}
135
136void TSocketPool::setRandomize(bool randomize) {
137 randomize_ = randomize;
138}
139
140void TSocketPool::setAlwaysTryLast(bool alwaysTryLast) {
141 alwaysTryLast_ = alwaysTryLast;
142}
143
David Reiss1997f102008-04-29 00:29:41 +0000144void TSocketPool::setCurrentServer(const shared_ptr<TSocketPoolServer> &server) {
145 currentServer_ = server;
146 host_ = server->host_;
147 port_ = server->port_;
148 socket_ = server->socket_;
149}
150
jsobele02e4242007-05-08 17:51:49 +0000151/* TODO: without apc we ignore a lot of functionality from the php version */
152void TSocketPool::open() {
153 if (randomize_) {
David Reiss8f3bce42008-03-18 18:21:52 +0000154 random_shuffle(servers_.begin(), servers_.end());
jsobele02e4242007-05-08 17:51:49 +0000155 }
156
David Reiss6d0cccd2008-02-28 21:20:12 +0000157 unsigned int numServers = servers_.size();
158 for (unsigned int i = 0; i < numServers; ++i) {
jsobele02e4242007-05-08 17:51:49 +0000159
David Reiss1997f102008-04-29 00:29:41 +0000160 shared_ptr<TSocketPoolServer> &server = servers_[i];
161 bool retryIntervalPassed = (server->lastFailTime_ == 0);
David Reiss6d0cccd2008-02-28 21:20:12 +0000162 bool isLastServer = alwaysTryLast_ ? (i == (numServers - 1)) : false;
jsobele02e4242007-05-08 17:51:49 +0000163
David Reiss1997f102008-04-29 00:29:41 +0000164 // Impersonate the server socket
165 setCurrentServer(server);
David Reissf50021a2008-02-29 07:33:47 +0000166
David Reiss1997f102008-04-29 00:29:41 +0000167 if (isOpen()) {
168 // already open means we're done
169 return;
170 }
171
172 if (server->lastFailTime_ > 0) {
David Reiss6d0cccd2008-02-28 21:20:12 +0000173 // The server was marked as down, so check if enough time has elapsed to retry
David Reiss1997f102008-04-29 00:29:41 +0000174 int elapsedTime = time(NULL) - server->lastFailTime_;
David Reiss6d0cccd2008-02-28 21:20:12 +0000175 if (elapsedTime > retryInterval_) {
176 retryIntervalPassed = true;
jsobele02e4242007-05-08 17:51:49 +0000177 }
178 }
David Reiss6d0cccd2008-02-28 21:20:12 +0000179
180 if (retryIntervalPassed || isLastServer) {
181 for (int j = 0; j < numRetries_; ++j) {
182 try {
183 TSocket::open();
184
David Reiss1997f102008-04-29 00:29:41 +0000185 // Copy over the opened socket so that we can keep it persistent
186 server->socket_ = socket_;
187
David Reiss6d0cccd2008-02-28 21:20:12 +0000188 // reset lastFailTime_ is required
David Reiss1997f102008-04-29 00:29:41 +0000189 if (server->lastFailTime_) {
190 server->lastFailTime_ = 0;
David Reiss6d0cccd2008-02-28 21:20:12 +0000191 }
192
193 // success
194 return;
195 } catch (TException e) {
David Reiss1997f102008-04-29 00:29:41 +0000196 string errStr = "TSocketPool::open failed "+getSocketInfo()+": "+e.what();
197 GlobalOutput(errStr.c_str());
David Reiss6d0cccd2008-02-28 21:20:12 +0000198 // connection failed
199 }
200 }
David Reiss6d0cccd2008-02-28 21:20:12 +0000201
David Reiss1997f102008-04-29 00:29:41 +0000202 ++server->consecutiveFailures_;
203 if (server->consecutiveFailures_ > maxConsecutiveFailures_) {
David Reiss8f3bce42008-03-18 18:21:52 +0000204 // Mark server as down
David Reiss1997f102008-04-29 00:29:41 +0000205 server->consecutiveFailures_ = 0;
206 server->lastFailTime_ = time(NULL);
David Reiss8f3bce42008-03-18 18:21:52 +0000207 }
David Reiss6d0cccd2008-02-28 21:20:12 +0000208 }
jsobele02e4242007-05-08 17:51:49 +0000209 }
210
boz6ded7752007-06-05 22:41:18 +0000211 GlobalOutput("TSocketPool::open: all connections failed");
jsobele02e4242007-05-08 17:51:49 +0000212 throw TTransportException(TTransportException::NOT_OPEN);
213}
214
David Reiss1997f102008-04-29 00:29:41 +0000215void TSocketPool::close() {
216 if (isOpen()) {
217 TSocket::close();
218 currentServer_->socket_ = -1;
219 }
220}
221
T Jake Lucianib5e62212009-01-31 22:36:20 +0000222}}} // apache::thrift::transport