blob: d1d5bcdcce6159d067377acf583230dc8fff4735 [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
16/**
David Reiss6d0cccd2008-02-28 21:20:12 +000017 * TSocketPoolServer implementation
18 *
19 * @author Akhil Wable <akhil@facebook.com>
20 */
21TSocketPoolServer::TSocketPoolServer()
22 : host_(""),
23 port_(0),
24 lastFailTime_(0),
25 consecutiveFailures_(0) {}
26
27/**
28 * Constructor for TSocketPool server
29 */
30TSocketPoolServer::TSocketPoolServer(const std::string &host, int port)
31 : host_(host),
32 port_(port),
33 lastFailTime_(0),
34 consecutiveFailures_(0) {}
35
36/**
jsobele02e4242007-05-08 17:51:49 +000037 * TSocketPool implementation.
38 *
39 * @author Jason Sobel <jsobel@facebook.com>
40 */
41
42TSocketPool::TSocketPool(const vector<string> &hosts,
43 const vector<int> &ports) : TSocket(),
44 numRetries_(1),
45 retryInterval_(60),
46 maxConsecutiveFailures_(1),
47 randomize_(true),
48 alwaysTryLast_(true)
49{
50 if (hosts.size() != ports.size()) {
boz6ded7752007-06-05 22:41:18 +000051 GlobalOutput("TSocketPool::TSocketPool: hosts.size != ports.size");
jsobele02e4242007-05-08 17:51:49 +000052 throw TTransportException(TTransportException::BAD_ARGS);
53 }
54
55 for (unsigned int i = 0; i < hosts.size(); ++i) {
dweatherfordd1372822007-10-09 22:57:23 +000056 addServer(hosts[i], ports[i]);
jsobele02e4242007-05-08 17:51:49 +000057 }
58}
59
David Reiss907ad762008-03-02 00:25:58 +000060TSocketPool::TSocketPool(const std::vector<pair<string, int> >& servers) : TSocket(),
jsobele02e4242007-05-08 17:51:49 +000061 numRetries_(1),
62 retryInterval_(60),
63 maxConsecutiveFailures_(1),
64 randomize_(true),
65 alwaysTryLast_(true)
66{
David Reiss6d0cccd2008-02-28 21:20:12 +000067 for (unsigned i = 0; i < servers.size(); ++i) {
68 addServer(servers[i].first, servers[i].second);
69 }
jsobele02e4242007-05-08 17:51:49 +000070}
71
David Reiss907ad762008-03-02 00:25:58 +000072TSocketPool::TSocketPool(const std::vector<TSocketPoolServer>& servers) : TSocket(),
73 servers_(servers),
74 numRetries_(1),
75 retryInterval_(60),
76 maxConsecutiveFailures_(1),
77 randomize_(true),
78 alwaysTryLast_(true)
79{
80}
81
dweatherfordd1372822007-10-09 22:57:23 +000082TSocketPool::TSocketPool(const string& host, int port) : TSocket(),
83 numRetries_(1),
84 retryInterval_(60),
85 maxConsecutiveFailures_(1),
86 randomize_(true),
87 alwaysTryLast_(true)
88{
89 addServer(host, port);
90}
91
jsobele02e4242007-05-08 17:51:49 +000092TSocketPool::~TSocketPool() {
93 close();
94}
95
dweatherfordd1372822007-10-09 22:57:23 +000096void TSocketPool::addServer(const string& host, int port) {
David Reiss6d0cccd2008-02-28 21:20:12 +000097 servers_.push_back(TSocketPoolServer(host, port));
dweatherfordd1372822007-10-09 22:57:23 +000098}
99
David Reiss907ad762008-03-02 00:25:58 +0000100std::vector<TSocketPoolServer> TSocketPool::getServers() {
101 return servers_;
102}
103
jsobele02e4242007-05-08 17:51:49 +0000104void TSocketPool::setNumRetries(int numRetries) {
105 numRetries_ = numRetries;
106}
107
108void TSocketPool::setRetryInterval(int retryInterval) {
109 retryInterval_ = retryInterval;
110}
111
112
113void TSocketPool::setMaxConsecutiveFailures(int maxConsecutiveFailures) {
114 maxConsecutiveFailures_ = maxConsecutiveFailures;
115}
116
117void TSocketPool::setRandomize(bool randomize) {
118 randomize_ = randomize;
119}
120
121void TSocketPool::setAlwaysTryLast(bool alwaysTryLast) {
122 alwaysTryLast_ = alwaysTryLast;
123}
124
125/* TODO: without apc we ignore a lot of functionality from the php version */
126void TSocketPool::open() {
127 if (randomize_) {
128 std::random_shuffle(servers_.begin(), servers_.end());
129 }
130
David Reiss6d0cccd2008-02-28 21:20:12 +0000131 unsigned int numServers = servers_.size();
132 for (unsigned int i = 0; i < numServers; ++i) {
jsobele02e4242007-05-08 17:51:49 +0000133
David Reiss6d0cccd2008-02-28 21:20:12 +0000134 TSocketPoolServer &server = servers_[i];
135 bool retryIntervalPassed = (server.lastFailTime_ == 0);
136 bool isLastServer = alwaysTryLast_ ? (i == (numServers - 1)) : false;
jsobele02e4242007-05-08 17:51:49 +0000137
David Reissf50021a2008-02-29 07:33:47 +0000138 host_ = server.host_;
139 port_ = server.port_;
140
David Reiss6d0cccd2008-02-28 21:20:12 +0000141 if (server.lastFailTime_ > 0) {
142 // The server was marked as down, so check if enough time has elapsed to retry
143 int elapsedTime = time(NULL) - server.lastFailTime_;
144 if (elapsedTime > retryInterval_) {
145 retryIntervalPassed = true;
jsobele02e4242007-05-08 17:51:49 +0000146 }
147 }
David Reiss6d0cccd2008-02-28 21:20:12 +0000148
149 if (retryIntervalPassed || isLastServer) {
150 for (int j = 0; j < numRetries_; ++j) {
151 try {
152 TSocket::open();
153
154 // reset lastFailTime_ is required
155 if (server.lastFailTime_) {
156 server.lastFailTime_ = 0;
157 }
158
159 // success
160 return;
161 } catch (TException e) {
162 // connection failed
163 }
164 }
165 }
166
167 ++server.consecutiveFailures_;
168 if (server.consecutiveFailures_ > maxConsecutiveFailures_) {
169 // Mark server as down
170 server.consecutiveFailures_ = 0;
171 server.lastFailTime_ = time(NULL);
172 }
jsobele02e4242007-05-08 17:51:49 +0000173 }
174
boz6ded7752007-06-05 22:41:18 +0000175 GlobalOutput("TSocketPool::open: all connections failed");
jsobele02e4242007-05-08 17:51:49 +0000176 throw TTransportException(TTransportException::NOT_OPEN);
177}
178
179}}} // facebook::thrift::transport