blob: d5a65012126420bebf27a5bf3a5791272ce03e46 [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
David Reiss0c90f6f2008-02-06 22:18:40 +000012namespace facebook { 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 *
21 * @author Akhil Wable <akhil@facebook.com>
22 */
23TSocketPoolServer::TSocketPoolServer()
24 : host_(""),
25 port_(0),
David Reiss1997f102008-04-29 00:29:41 +000026 socket_(-1),
David Reiss6d0cccd2008-02-28 21:20:12 +000027 lastFailTime_(0),
28 consecutiveFailures_(0) {}
29
30/**
31 * Constructor for TSocketPool server
32 */
David Reiss8f3bce42008-03-18 18:21:52 +000033TSocketPoolServer::TSocketPoolServer(const string &host, int port)
David Reiss6d0cccd2008-02-28 21:20:12 +000034 : host_(host),
35 port_(port),
David Reiss1997f102008-04-29 00:29:41 +000036 socket_(-1),
David Reiss6d0cccd2008-02-28 21:20:12 +000037 lastFailTime_(0),
38 consecutiveFailures_(0) {}
39
40/**
jsobele02e4242007-05-08 17:51:49 +000041 * TSocketPool implementation.
42 *
43 * @author Jason Sobel <jsobel@facebook.com>
44 */
45
David Reiss8f3bce42008-03-18 18:21:52 +000046TSocketPool::TSocketPool() : TSocket(),
47 numRetries_(1),
48 retryInterval_(60),
49 maxConsecutiveFailures_(1),
50 randomize_(true),
51 alwaysTryLast_(true) {
52}
53
jsobele02e4242007-05-08 17:51:49 +000054TSocketPool::TSocketPool(const vector<string> &hosts,
55 const vector<int> &ports) : TSocket(),
56 numRetries_(1),
57 retryInterval_(60),
58 maxConsecutiveFailures_(1),
59 randomize_(true),
60 alwaysTryLast_(true)
61{
62 if (hosts.size() != ports.size()) {
boz6ded7752007-06-05 22:41:18 +000063 GlobalOutput("TSocketPool::TSocketPool: hosts.size != ports.size");
jsobele02e4242007-05-08 17:51:49 +000064 throw TTransportException(TTransportException::BAD_ARGS);
65 }
66
67 for (unsigned int i = 0; i < hosts.size(); ++i) {
dweatherfordd1372822007-10-09 22:57:23 +000068 addServer(hosts[i], ports[i]);
jsobele02e4242007-05-08 17:51:49 +000069 }
70}
71
David Reiss8f3bce42008-03-18 18:21:52 +000072TSocketPool::TSocketPool(const vector<pair<string, int> >& servers) : TSocket(),
jsobele02e4242007-05-08 17:51:49 +000073 numRetries_(1),
74 retryInterval_(60),
75 maxConsecutiveFailures_(1),
76 randomize_(true),
77 alwaysTryLast_(true)
78{
David Reiss6d0cccd2008-02-28 21:20:12 +000079 for (unsigned i = 0; i < servers.size(); ++i) {
80 addServer(servers[i].first, servers[i].second);
81 }
jsobele02e4242007-05-08 17:51:49 +000082}
83
David Reiss8f3bce42008-03-18 18:21:52 +000084TSocketPool::TSocketPool(const vector< shared_ptr<TSocketPoolServer> >& servers) : TSocket(),
David Reiss907ad762008-03-02 00:25:58 +000085 servers_(servers),
86 numRetries_(1),
87 retryInterval_(60),
88 maxConsecutiveFailures_(1),
89 randomize_(true),
90 alwaysTryLast_(true)
91{
92}
93
dweatherfordd1372822007-10-09 22:57:23 +000094TSocketPool::TSocketPool(const string& host, int port) : TSocket(),
95 numRetries_(1),
96 retryInterval_(60),
97 maxConsecutiveFailures_(1),
98 randomize_(true),
99 alwaysTryLast_(true)
100{
101 addServer(host, port);
102}
103
jsobele02e4242007-05-08 17:51:49 +0000104TSocketPool::~TSocketPool() {
David Reiss1997f102008-04-29 00:29:41 +0000105 vector< shared_ptr<TSocketPoolServer> >::const_iterator iter = servers_.begin();
106 vector< shared_ptr<TSocketPoolServer> >::const_iterator iterEnd = servers_.end();
107 for (; iter != iterEnd; ++iter) {
108 setCurrentServer(*iter);
109 TSocketPool::close();
110 }
jsobele02e4242007-05-08 17:51:49 +0000111}
112
dweatherfordd1372822007-10-09 22:57:23 +0000113void TSocketPool::addServer(const string& host, int port) {
David Reiss8f3bce42008-03-18 18:21:52 +0000114 servers_.push_back(shared_ptr<TSocketPoolServer>(new TSocketPoolServer(host, port)));
dweatherfordd1372822007-10-09 22:57:23 +0000115}
116
David Reiss8f3bce42008-03-18 18:21:52 +0000117void TSocketPool::setServers(const vector< shared_ptr<TSocketPoolServer> >& servers) {
118 servers_ = servers;
119}
120
121void TSocketPool::getServers(vector< shared_ptr<TSocketPoolServer> >& servers) {
122 servers = servers_;
David Reiss907ad762008-03-02 00:25:58 +0000123}
124
jsobele02e4242007-05-08 17:51:49 +0000125void TSocketPool::setNumRetries(int numRetries) {
126 numRetries_ = numRetries;
127}
128
129void TSocketPool::setRetryInterval(int retryInterval) {
130 retryInterval_ = retryInterval;
131}
132
133
134void TSocketPool::setMaxConsecutiveFailures(int maxConsecutiveFailures) {
135 maxConsecutiveFailures_ = maxConsecutiveFailures;
136}
137
138void TSocketPool::setRandomize(bool randomize) {
139 randomize_ = randomize;
140}
141
142void TSocketPool::setAlwaysTryLast(bool alwaysTryLast) {
143 alwaysTryLast_ = alwaysTryLast;
144}
145
David Reiss1997f102008-04-29 00:29:41 +0000146void TSocketPool::setCurrentServer(const shared_ptr<TSocketPoolServer> &server) {
147 currentServer_ = server;
148 host_ = server->host_;
149 port_ = server->port_;
150 socket_ = server->socket_;
151}
152
jsobele02e4242007-05-08 17:51:49 +0000153/* TODO: without apc we ignore a lot of functionality from the php version */
154void TSocketPool::open() {
155 if (randomize_) {
David Reiss8f3bce42008-03-18 18:21:52 +0000156 random_shuffle(servers_.begin(), servers_.end());
jsobele02e4242007-05-08 17:51:49 +0000157 }
158
David Reiss6d0cccd2008-02-28 21:20:12 +0000159 unsigned int numServers = servers_.size();
160 for (unsigned int i = 0; i < numServers; ++i) {
jsobele02e4242007-05-08 17:51:49 +0000161
David Reiss1997f102008-04-29 00:29:41 +0000162 shared_ptr<TSocketPoolServer> &server = servers_[i];
163 bool retryIntervalPassed = (server->lastFailTime_ == 0);
David Reiss6d0cccd2008-02-28 21:20:12 +0000164 bool isLastServer = alwaysTryLast_ ? (i == (numServers - 1)) : false;
jsobele02e4242007-05-08 17:51:49 +0000165
David Reiss1997f102008-04-29 00:29:41 +0000166 // Impersonate the server socket
167 setCurrentServer(server);
David Reissf50021a2008-02-29 07:33:47 +0000168
David Reiss1997f102008-04-29 00:29:41 +0000169 if (isOpen()) {
170 // already open means we're done
171 return;
172 }
173
174 if (server->lastFailTime_ > 0) {
David Reiss6d0cccd2008-02-28 21:20:12 +0000175 // The server was marked as down, so check if enough time has elapsed to retry
David Reiss1997f102008-04-29 00:29:41 +0000176 int elapsedTime = time(NULL) - server->lastFailTime_;
David Reiss6d0cccd2008-02-28 21:20:12 +0000177 if (elapsedTime > retryInterval_) {
178 retryIntervalPassed = true;
jsobele02e4242007-05-08 17:51:49 +0000179 }
180 }
David Reiss6d0cccd2008-02-28 21:20:12 +0000181
182 if (retryIntervalPassed || isLastServer) {
183 for (int j = 0; j < numRetries_; ++j) {
184 try {
185 TSocket::open();
186
David Reiss1997f102008-04-29 00:29:41 +0000187 // Copy over the opened socket so that we can keep it persistent
188 server->socket_ = socket_;
189
David Reiss6d0cccd2008-02-28 21:20:12 +0000190 // reset lastFailTime_ is required
David Reiss1997f102008-04-29 00:29:41 +0000191 if (server->lastFailTime_) {
192 server->lastFailTime_ = 0;
David Reiss6d0cccd2008-02-28 21:20:12 +0000193 }
194
195 // success
196 return;
197 } catch (TException e) {
David Reiss1997f102008-04-29 00:29:41 +0000198 string errStr = "TSocketPool::open failed "+getSocketInfo()+": "+e.what();
199 GlobalOutput(errStr.c_str());
David Reiss6d0cccd2008-02-28 21:20:12 +0000200 // connection failed
201 }
202 }
David Reiss6d0cccd2008-02-28 21:20:12 +0000203
David Reiss1997f102008-04-29 00:29:41 +0000204 ++server->consecutiveFailures_;
205 if (server->consecutiveFailures_ > maxConsecutiveFailures_) {
David Reiss8f3bce42008-03-18 18:21:52 +0000206 // Mark server as down
David Reiss1997f102008-04-29 00:29:41 +0000207 server->consecutiveFailures_ = 0;
208 server->lastFailTime_ = time(NULL);
David Reiss8f3bce42008-03-18 18:21:52 +0000209 }
David Reiss6d0cccd2008-02-28 21:20:12 +0000210 }
jsobele02e4242007-05-08 17:51:49 +0000211 }
212
boz6ded7752007-06-05 22:41:18 +0000213 GlobalOutput("TSocketPool::open: all connections failed");
jsobele02e4242007-05-08 17:51:49 +0000214 throw TTransportException(TTransportException::NOT_OPEN);
215}
216
David Reiss1997f102008-04-29 00:29:41 +0000217void TSocketPool::close() {
218 if (isOpen()) {
219 TSocket::close();
220 currentServer_->socket_ = -1;
221 }
222}
223
jsobele02e4242007-05-08 17:51:49 +0000224}}} // facebook::thrift::transport